Merge branch '0.7.0-dev' of https://github.com/Nheko-Reborn/nheko into 0.7.0-dev

This commit is contained in:
Joe 2019-11-02 00:27:54 -04:00
commit 35759d2c6c
64 changed files with 3831 additions and 1523 deletions

View file

@ -4,6 +4,10 @@ set -ex
if [ "$TRAVIS_OS_NAME" = "osx" ]; then if [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update brew update
# uninstall packages, that would get upgraded by upgrading cmake (and we don't need)
brew uninstall --force cgal node sfcgal postgis
brew install qt5 lmdb clang-format ninja libsodium cmark brew install qt5 lmdb clang-format ninja libsodium cmark
brew upgrade boost cmake icu4c || true brew upgrade boost cmake icu4c || true

View file

@ -25,8 +25,8 @@ for iconSize in 16 32 48 64 128 256 512; do
done done
# Only download the file when not already present # Only download the file when not already present
if ! [ -f linuxdeployqt-continuous-x86_64.AppImage ] ; then if ! [ -f linuxdeployqt-6-x86_64.AppImage ] ; then
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/6/linuxdeployqt-6-x86_64.AppImage"
fi fi
chmod a+x linuxdeployqt*.AppImage chmod a+x linuxdeployqt*.AppImage
@ -49,7 +49,10 @@ done
chmod +x nheko-*x86_64.AppImage chmod +x nheko-*x86_64.AppImage
if [ ! -z "$VERSION" ]; then mkdir artifacts
cp nheko-*x86_64.AppImage artifacts/
if [ -n "$VERSION" ]; then
# commented out for now, as AppImage file appears to already contain the version. # commented out for now, as AppImage file appears to already contain the version.
#mv nheko-*x86_64.AppImage nheko-${VERSION}-x86_64.AppImage #mv nheko-*x86_64.AppImage nheko-${VERSION}-x86_64.AppImage
echo "nheko-${VERSION}-x86_64.AppImage" echo "nheko-${VERSION}-x86_64.AppImage"

View file

@ -25,6 +25,8 @@ PATH=/usr/local/opt/qt/bin/:${PATH}
dmgbuild -s ./.ci/macos/settings.json "Nheko" nheko.dmg dmgbuild -s ./.ci/macos/settings.json "Nheko" nheko.dmg
if [ ! -z "$VERSION" ]; then if [ -n "$VERSION" ]; then
mv nheko.dmg "nheko-${VERSION}.dmg" mv nheko.dmg "nheko-${VERSION}.dmg"
mkdir artifacts
cp "nheko-${VERSION}.dmg" artifacts/
fi fi

View file

@ -28,7 +28,8 @@ fi
cmake -GNinja -Hdeps -B.deps \ cmake -GNinja -Hdeps -B.deps \
-DUSE_BUNDLED_BOOST="${USE_BUNDLED_BOOST}" \ -DUSE_BUNDLED_BOOST="${USE_BUNDLED_BOOST}" \
-DUSE_BUNDLED_CMARK="${USE_BUNDLED_CMARK}" \ -DUSE_BUNDLED_CMARK="${USE_BUNDLED_CMARK}" \
-DUSE_BUNDLED_JSON="${USE_BUNDLED_JSON}" -DUSE_BUNDLED_JSON="${USE_BUNDLED_JSON}" \
-DMTX_STATIC="${MTX_STATIC:-OFF}"
cmake --build .deps cmake --build .deps
# Build nheko # Build nheko
@ -40,11 +41,11 @@ cmake --build build
if [ "$TRAVIS_OS_NAME" = "osx" ]; then if [ "$TRAVIS_OS_NAME" = "osx" ]; then
make lint; make lint;
if [ "$DEPLOYMENT" = 1 ] && [ ! -z "$VERSION" ] ; then if [ "$DEPLOYMENT" = 1 ] && [ -n "$VERSION" ] ; then
make macos-deploy; make macos-deploy;
fi fi
fi fi
if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$DEPLOYMENT" = 1 ] && [ ! -z "$VERSION" ]; then if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$DEPLOYMENT" = 1 ] && [ -n "$VERSION" ]; then
make linux-deploy; make linux-deploy;
fi fi

6
.gitignore vendored
View file

@ -1,8 +1,14 @@
build build
tags tags
cscope*
.clang_complete .clang_complete
*wintoastlib* *wintoastlib*
# GTAGS
GTAGS
GRTAGS
GPATH
# C++ objects and libs # C++ objects and libs
*.slo *.slo

View file

@ -21,6 +21,7 @@ matrix:
- USE_BUNDLED_BOOST=0 - USE_BUNDLED_BOOST=0
- USE_BUNDLED_CMARK=0 - USE_BUNDLED_CMARK=0
- USE_BUNDLED_JSON=0 - USE_BUNDLED_JSON=0
- MTX_STATIC=1
- os: linux - os: linux
compiler: gcc compiler: gcc
env: env:
@ -79,6 +80,21 @@ script:
- sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true - sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true
- cp ./.ci/bintray-release.json . - cp ./.ci/bintray-release.json .
deploy: deploy:
- provider: s3
access_key_id: $ARTIFACTS_KEY
secret_access_key: $ARTIFACTS_SECRET
bucket: $ARTIFACTS_BUCKET
region: $AWS_DEFAULT_REGION
detect_encoding: true
cache_control: "max-age=31536000"
skip_cleanup: true
acl: public_read
local_dir: artifacts
on:
condition: "$DEPLOYMENT == 1"
repo: Nheko-Reborn/nheko
tags: false
all_branches: true
- provider: bintray - provider: bintray
user: "redsky17" user: "redsky17"
key: key:

View file

@ -4,13 +4,22 @@
### [0.7.0] -- Unreleased ### [0.7.0] -- Unreleased
0.7.0 *requires* mtxclient 0.3.0. Make sure you compile against 0.3.0
if you do not use the mtxclient bundled with nheko.
#### Features #### Features
- Make nheko session import / export format match riot. Fixes #48 (WIP) - Make nheko session import / export format match riot. Fixes #48 (WIP)
- Implement proper replies (WIP) - Implement proper replies (WIP)
- Add .well-known support for auto-completing homeserver information
- Add mentions viewer so you can see all the messages you have been mentioned in (WIP)
- Add emoji font selection preference
#### Improvements #### Improvements
- Add dedicated reply button to Timeline items. Add button for other options so - Add dedicated reply button to Timeline items. Add button for other options so
that right click isn't always required. that right click isn't always required.
- Fix various things with regards to emoji rendering and the emoji picker (WIP)
- Lots and lots and lots of localization updates.
- Additional tweaks to the system theme
## [0.6.4] - 2019-05-22 ## [0.6.4] - 2019-05-22

View file

@ -179,7 +179,6 @@ set(SRC_FILES
src/dialogs/LeaveRoom.cpp src/dialogs/LeaveRoom.cpp
src/dialogs/Logout.cpp src/dialogs/Logout.cpp
src/dialogs/UserProfile.cpp src/dialogs/UserProfile.cpp
src/dialogs/UserMentions.cpp
src/dialogs/ReadReceipts.cpp src/dialogs/ReadReceipts.cpp
src/dialogs/ReCaptcha.cpp src/dialogs/ReCaptcha.cpp
src/dialogs/RoomSettings.cpp src/dialogs/RoomSettings.cpp
@ -241,13 +240,13 @@ set(SRC_FILES
src/popups/SuggestionsPopup.cpp src/popups/SuggestionsPopup.cpp
src/popups/PopupItem.cpp src/popups/PopupItem.cpp
src/popups/ReplyPopup.cpp src/popups/ReplyPopup.cpp
src/popups/UserMentions.cpp
src/TextInputWidget.cpp src/TextInputWidget.cpp
src/TopRoomBar.cpp src/TopRoomBar.cpp
src/TrayIcon.cpp src/TrayIcon.cpp
src/TypingDisplay.cpp src/TypingDisplay.cpp
src/Utils.cpp src/Utils.cpp
src/UserInfoWidget.cpp src/UserInfoWidget.cpp
src/UserMentionsWidget.cpp
src/UserSettingsPage.cpp src/UserSettingsPage.cpp
src/WelcomePage.cpp src/WelcomePage.cpp
src/main.cpp src/main.cpp
@ -321,7 +320,6 @@ qt5_wrap_cpp(MOC_HEADERS
src/dialogs/MemberList.h src/dialogs/MemberList.h
src/dialogs/LeaveRoom.h src/dialogs/LeaveRoom.h
src/dialogs/Logout.h src/dialogs/Logout.h
src/dialogs/UserMentions.h
src/dialogs/UserProfile.h src/dialogs/UserProfile.h
src/dialogs/RawMessage.h src/dialogs/RawMessage.h
src/dialogs/ReadReceipts.h src/dialogs/ReadReceipts.h
@ -383,12 +381,12 @@ qt5_wrap_cpp(MOC_HEADERS
src/popups/SuggestionsPopup.h src/popups/SuggestionsPopup.h
src/popups/ReplyPopup.h src/popups/ReplyPopup.h
src/popups/PopupItem.h src/popups/PopupItem.h
src/popups/UserMentions.h
src/TextInputWidget.h src/TextInputWidget.h
src/TopRoomBar.h src/TopRoomBar.h
src/TrayIcon.h src/TrayIcon.h
src/TypingDisplay.h src/TypingDisplay.h
src/UserInfoWidget.h src/UserInfoWidget.h
src/UserMentionsWidget.h
src/UserSettingsPage.h src/UserSettingsPage.h
src/WelcomePage.h src/WelcomePage.h
) )

View file

@ -3,7 +3,7 @@ nheko
[![Build Status](https://travis-ci.org/Nheko-Reborn/nheko.svg?branch=master)](https://travis-ci.org/Nheko-Reborn/nheko) [![Build Status](https://travis-ci.org/Nheko-Reborn/nheko.svg?branch=master)](https://travis-ci.org/Nheko-Reborn/nheko)
[![Build status](https://ci.appveyor.com/api/projects/status/07qrqbfylsg4hw2h/branch/master?svg=true)](https://ci.appveyor.com/project/redsky17/nheko/branch/master) [![Build status](https://ci.appveyor.com/api/projects/status/07qrqbfylsg4hw2h/branch/master?svg=true)](https://ci.appveyor.com/project/redsky17/nheko/branch/master)
[![Stable Version](https://img.shields.io/badge/download-stable-green.svg)](https://github.com/Nheko-Reborn/nheko/releases/v0.6.4) [![Stable Version](https://img.shields.io/badge/download-stable-green.svg)](https://github.com/Nheko-Reborn/nheko/releases/v0.6.4)
[![Nightly](https://img.shields.io/badge/download-nightly-green.svg)](https://bintray.com/nheko-reborn/nheko/nheko) [![Nightly](https://img.shields.io/badge/download-nightly-green.svg)](https://nheko-reborn-artifacts.s3.us-east-2.amazonaws.com/list.html)
[![#nheko-reborn:matrix.org](https://img.shields.io/matrix/nheko-reborn:matrix.org.svg?label=%23nheko-reborn:matrix.org)](https://matrix.to/#/#nheko-reborn:matrix.org) [![#nheko-reborn:matrix.org](https://img.shields.io/matrix/nheko-reborn:matrix.org.svg?label=%23nheko-reborn:matrix.org)](https://matrix.to/#/#nheko-reborn:matrix.org)
[![AUR: nheko](https://img.shields.io/badge/AUR-nheko-blue.svg)](https://aur.archlinux.org/packages/nheko) [![AUR: nheko](https://img.shields.io/badge/AUR-nheko-blue.svg)](https://aur.archlinux.org/packages/nheko)
<a href='https://flathub.org/apps/details/io.github.NhekoReborn.Nheko'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a> <a href='https://flathub.org/apps/details/io.github.NhekoReborn.Nheko'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>

4
deps/CMakeLists.txt vendored
View file

@ -46,10 +46,10 @@ set(BOOST_SHA256
set( set(
MTXCLIENT_URL MTXCLIENT_URL
https://github.com/Nheko-Reborn/mtxclient/archive/37df82363c800b8d6b2b172a486e395e4132e061.tar.gz https://github.com/Nheko-Reborn/mtxclient/archive/6eee767cc25a9db9f125843e584656cde1ebb6c5.tar.gz
) )
set(MTXCLIENT_HASH set(MTXCLIENT_HASH
b29dd0bc836b69bd4253499519b8396a210bba43750fb66f4ffb8453510c8dd1) 72fe77da4fed98b3cf069299f66092c820c900359a27ec26070175f9ad208a03)
set( set(
TWEENY_URL TWEENY_URL
https://github.com/mobius3/tweeny/archive/b94ce07cfb02a0eb8ac8aaf66137dabdaea857cf.tar.gz https://github.com/mobius3/tweeny/archive/b94ce07cfb02a0eb8ac8aaf66137dabdaea857cf.tar.gz

View file

@ -3,6 +3,10 @@ if(WIN32)
return() return()
endif() endif()
include(BoostToolsetId)
set(BOOST_TOOLSET "gcc")
Boost_Get_ToolsetId(BOOST_TOOLSET)
ExternalProject_Add( ExternalProject_Add(
Boost Boost
@ -16,6 +20,7 @@ ExternalProject_Add(
CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/boost/bootstrap.sh CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/boost/bootstrap.sh
--with-libraries=random,thread,system,iostreams,atomic,chrono,date_time,regex --with-libraries=random,thread,system,iostreams,atomic,chrono,date_time,regex
--prefix=${DEPS_INSTALL_DIR} --prefix=${DEPS_INSTALL_DIR}
--with-toolset=${BOOST_TOOLSET}
BUILD_COMMAND ${DEPS_BUILD_DIR}/boost/b2 -d0 cxxstd=14 variant=release link=shared runtime-link=shared threading=multi --layout=system BUILD_COMMAND ${DEPS_BUILD_DIR}/boost/b2 -d0 cxxstd=14 variant=release link=shared runtime-link=shared threading=multi --layout=system
INSTALL_COMMAND ${DEPS_BUILD_DIR}/boost/b2 -d0 install INSTALL_COMMAND ${DEPS_BUILD_DIR}/boost/b2 -d0 install
) )

35
deps/cmake/BoostToolsetId.cmake vendored Normal file
View file

@ -0,0 +1,35 @@
# - Translate CMake compilers to the Boost.Build toolset equivalents
# To build Boost reliably when a non-system compiler may be used, we
# need to both specify the toolset when running bootstrap.sh *and* in
# the user-config.jam file.
#
# This module provides the following functions to help translate between
# the systems:
#
# function Boost_Get_ToolsetId(<var>)
# Set var equal to Boost's name for the CXX toolchain picked
# up by CMake. Only supports GNU and Clang families at present.
# Intel support is provisional
#
# downloaded from https://github.com/drbenmorgan/BoostBuilder/blob/master/BoostToolsetId.cmake
function(Boost_Get_ToolsetId _var)
set(BOOST_TOOLSET)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if(APPLE)
set(BOOST_TOOLSET "darwin")
else()
set(BOOST_TOOLSET "gcc")
endif()
elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
set(BOOST_TOOLSET "clang")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
set(BOOST_TOOLSET "intel")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(BOOST_TOOLSET "msvc")
endif()
set(${_var} ${BOOST_TOOLSET} PARENT_SCOPE)
endfunction()

View file

@ -4,17 +4,17 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation>Datei speichern</translation> <translation>In Datei speichern</translation>
</message> </message>
</context> </context>
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation>Hochladen der Bilddatei fehlgeschlagen. Bitte versuche es erneut.</translation> <translation>Hochladen des Bildes fehlgeschlagen. Bitte versuche es erneut.</translation>
</message> </message>
<message> <message>
<location line="+45"/> <location line="+45"/>
@ -32,25 +32,25 @@
<translation>Hochladen der Videodatei fehlgeschlagen. Bitte versuche es erneut.</translation> <translation>Hochladen der Videodatei fehlgeschlagen. Bitte versuche es erneut.</translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation type="unfinished"></translation> <translation>Wiederherstellung des OLM Accounts fehlgeschlagen. Bitte logge dich erneut ein.</translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Failed to restore save data. Please login again.</source> <source>Failed to restore save data. Please login again.</source>
<translation type="unfinished">Nachrichten konnten nicht aus dem Cache geladen werden. Bitte melde dich erneut an.</translation> <translation>Gespeicherte Nachrichten konnten nicht wiederhergestellt werden. Bitte melde Dich erneut an.</translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation type="unfinished"></translation> <translation>Fehler beim Setup der Verschlüsselungsschlüssel. Servermeldung: %1 %2. Bitte versuche es später erneut.</translation>
</message> </message>
<message> <message>
<location line="+51"/> <location line="+51"/>
<location line="+153"/> <location line="+153"/>
<source>Please try to login again: %1</source> <source>Please try to login again: %1</source>
<translation type="unfinished">Bitte melde dich erneut an: %1</translation> <translation>Bitte melde dich erneut an: %1</translation>
</message> </message>
<message> <message>
<location line="-45"/> <location line="-45"/>
@ -68,28 +68,28 @@
<message> <message>
<location filename="../../src/CommunitiesListItem.cpp" line="+130"/> <location filename="../../src/CommunitiesListItem.cpp" line="+130"/>
<source>All rooms</source> <source>All rooms</source>
<translation type="unfinished"></translation> <translation>Alle Räume</translation>
</message> </message>
<message> <message>
<location line="+4"/> <location line="+4"/>
<source>Favourite rooms</source> <source>Favourite rooms</source>
<translation type="unfinished"></translation> <translation>Favoriten</translation>
</message> </message>
<message> <message>
<location line="+2"/> <location line="+2"/>
<source>Low priority rooms</source> <source>Low priority rooms</source>
<translation type="unfinished"></translation> <translation>Räume niedriger Priorität</translation>
</message> </message>
<message> <message>
<location line="+2"/> <location line="+2"/>
<location line="+2"/> <location line="+2"/>
<source> (tag)</source> <source> (tag)</source>
<translation type="unfinished"></translation> <translation> (tag)</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source> (community)</source> <source> (community)</source>
<translation type="unfinished"></translation> <translation> (community)</translation>
</message> </message>
</context> </context>
<context> <context>
@ -97,17 +97,17 @@
<message> <message>
<location filename="../../src/dialogs/RoomSettings.cpp" line="+58"/> <location filename="../../src/dialogs/RoomSettings.cpp" line="+58"/>
<source>Apply</source> <source>Apply</source>
<translation type="unfinished"></translation> <translation>Anwenden</translation>
</message> </message>
<message> <message>
<location line="+1"/> <location line="+1"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+10"/> <location line="+10"/>
<source>Name</source> <source>Name</source>
<translation>Titel</translation> <translation>Name</translation>
</message> </message>
<message> <message>
<location line="+2"/> <location line="+2"/>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation>Datei speichern</translation> <translation>Datei speichern</translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation>Bild speichern</translation> <translation>Bild speichern</translation>
</message> </message>
@ -136,7 +136,7 @@
<message> <message>
<location filename="../../src/InviteeItem.cpp" line="+17"/> <location filename="../../src/InviteeItem.cpp" line="+17"/>
<source>Remove</source> <source>Remove</source>
<translation type="unfinished"></translation> <translation>Löschen</translation>
</message> </message>
</context> </context>
<context> <context>
@ -159,7 +159,7 @@
<message> <message>
<location line="+4"/> <location line="+4"/>
<source>Device name</source> <source>Device name</source>
<translation type="unfinished"></translation> <translation>Gerätename</translation>
</message> </message>
<message> <message>
<location line="+19"/> <location line="+19"/>
@ -169,27 +169,27 @@
<message> <message>
<location line="+84"/> <location line="+84"/>
<source>Autodiscovery failed. Received malformed response.</source> <source>Autodiscovery failed. Received malformed response.</source>
<translation type="unfinished"></translation> <translation>Automatische Erkennung fehlgeschlagen. Antwort war fehlerhaft.</translation>
</message> </message>
<message> <message>
<location line="+6"/> <location line="+6"/>
<source>Autodiscovery failed. Unknown error when requesting .well-known.</source> <source>Autodiscovery failed. Unknown error when requesting .well-known.</source>
<translation type="unfinished"></translation> <translation>Automatische Erkennung fehlgeschlagen. Unbekannter Fehler bei Anfrage .well-known.</translation>
</message> </message>
<message> <message>
<location line="+24"/> <location line="+24"/>
<source>The required endpoints were not found. Possibly not a Matrix server.</source> <source>The required endpoints were not found. Possibly not a Matrix server.</source>
<translation type="unfinished"></translation> <translation>Benötigte Ansprechpunkte nicht auffindbar. Möglicherweise kein Matrixserver.</translation>
</message> </message>
<message> <message>
<location line="+6"/> <location line="+6"/>
<source>Received malformed response. Make sure the homeserver domain is valid.</source> <source>Received malformed response. Make sure the homeserver domain is valid.</source>
<translation type="unfinished"></translation> <translation>Erhaltene Antwort war fehlerhaft. Bitte Homeserverdomain prüfen.</translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>An unknown error occured. Make sure the homeserver domain is valid.</source> <source>An unknown error occured. Make sure the homeserver domain is valid.</source>
<translation type="unfinished"></translation> <translation>Ein unbekannter Fehler ist aufgetreten. Bitte Homeserverdomain prüfen.</translation>
</message> </message>
<message> <message>
<location line="+60"/> <location line="+60"/>
@ -205,9 +205,9 @@
<translation>Teilnehmerliste</translation> <translation>Teilnehmerliste</translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation type="unfinished"></translation> <translation>OK</translation>
</message> </message>
</context> </context>
<context> <context>
@ -215,7 +215,7 @@
<message> <message>
<location filename="../../src/QuickSwitcher.cpp" line="+71"/> <location filename="../../src/QuickSwitcher.cpp" line="+71"/>
<source>Search for a room...</source> <source>Search for a room...</source>
<translation>Raum suchen...</translation> <translation>Raum suchen</translation>
</message> </message>
</context> </context>
<context> <context>
@ -238,7 +238,7 @@
<message> <message>
<location line="+4"/> <location line="+4"/>
<source>Home Server</source> <source>Home Server</source>
<translation>Heimserver</translation> <translation>Homeserver</translation>
</message> </message>
<message> <message>
<location line="+16"/> <location line="+16"/>
@ -263,7 +263,7 @@
<message> <message>
<location line="+2"/> <location line="+2"/>
<source>Invalid server name</source> <source>Invalid server name</source>
<translation>Ungültiger Server-Name</translation> <translation>Ungültiger Servername</translation>
</message> </message>
</context> </context>
<context> <context>
@ -271,28 +271,28 @@
<message> <message>
<location filename="../../src/popups/ReplyPopup.cpp" line="+45"/> <location filename="../../src/popups/ReplyPopup.cpp" line="+45"/>
<source>Logout</source> <source>Logout</source>
<translation type="unfinished"></translation> <translation>Abmelden</translation>
</message> </message>
</context> </context>
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation>keine Version gespeichert</translation>
</message> </message>
</context> </context>
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation>Raum verlassen</translation> <translation>Raum verlassen</translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation>Akzeptieren </translation> <translation>Akzeptieren</translation>
</message> </message>
<message> <message>
<location line="+1"/> <location line="+1"/>
@ -305,7 +305,7 @@
<message> <message>
<location filename="../../src/SideBarActions.cpp" line="+38"/> <location filename="../../src/SideBarActions.cpp" line="+38"/>
<source>User settings</source> <source>User settings</source>
<translation type="unfinished"></translation> <translation>Benutzereinstellungen</translation>
</message> </message>
<message> <message>
<location line="+7"/> <location line="+7"/>
@ -320,59 +320,59 @@
<message> <message>
<location line="+16"/> <location line="+16"/>
<source>Start a new chat</source> <source>Start a new chat</source>
<translation type="unfinished"></translation> <translation>Neues Gespräch beginnen</translation>
</message> </message>
<message> <message>
<location line="+15"/> <location line="+15"/>
<source>Room directory</source> <source>Room directory</source>
<translation type="unfinished"></translation> <translation>Raumverzeichnis</translation>
</message> </message>
</context> </context>
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation type="unfinished"></translation> <translation>Verschlüsselt</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>Delivered</source> <source>Delivered</source>
<translation type="unfinished"></translation> <translation>Erhalten</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>Seen</source> <source>Seen</source>
<translation type="unfinished"></translation> <translation>Gelesen</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>Sent</source> <source>Sent</source>
<translation type="unfinished"></translation> <translation>Gesendet</translation>
</message> </message>
</context> </context>
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation type="unfinished"></translation> <translation>Versende Datei</translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>Schreibe eine Nachricht...</translation> <translation>Schreibe eine Nachricht</translation>
</message> </message>
<message> <message>
<location line="+31"/> <location line="+31"/>
<source>Send a message</source> <source>Send a message</source>
<translation type="unfinished"></translation> <translation>Versende eine Nachricht</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
<source>Emoji</source> <source>Emoji</source>
<translation type="unfinished"></translation> <translation>Emoji</translation>
</message> </message>
<message> <message>
<location line="+75"/> <location line="+75"/>
@ -387,7 +387,7 @@
<message> <message>
<location filename="../../src/TextInputWidget.h" line="-5"/> <location filename="../../src/TextInputWidget.h" line="-5"/>
<source>Connection lost. Nheko is trying to re-connect...</source> <source>Connection lost. Nheko is trying to re-connect...</source>
<translation type="unfinished"></translation> <translation>Verbindung verloren. Nheko versucht sie wieder aufzunehmen</translation>
</message> </message>
</context> </context>
<context> <context>
@ -395,17 +395,17 @@
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+85"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+85"/>
<source>Message redaction failed: %1</source> <source>Message redaction failed: %1</source>
<translation type="unfinished"></translation> <translation>Nachricht zurückziehen fehlgeschlagen: %1</translation>
</message> </message>
<message> <message>
<location line="+39"/> <location line="+39"/>
<source>Reply</source> <source>Reply</source>
<translation type="unfinished"></translation> <translation>Antworten</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+11"/>
<source>Options</source> <source>Options</source>
<translation type="unfinished"></translation> <translation>Optionen</translation>
</message> </message>
</context> </context>
<context> <context>
@ -413,7 +413,37 @@
<message> <message>
<location filename="../../src/timeline/TimelineView.cpp" line="+245"/> <location filename="../../src/timeline/TimelineView.cpp" line="+245"/>
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation type="unfinished"></translation> <translation>Verschlüsselung aktiv</translation>
</message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation>-- verschlüsselter Event (keine Schlüssel zur Entschlüsselung gefunden) --</translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation>-- Entschlüsselungsfehler (Fehler bei Kommunikation mit Datenbank) --</translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation>-- Entschlüsselungsfehler (Fehler bei Suche nach megolm Schlüsseln in Datenbank) --</translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation>-- Entschlüsselungsfehler (%1) --</translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation>-- verschlüsselter Event (Unbekannter Eventtyp) --</translation>
</message> </message>
</context> </context>
<context> <context>
@ -421,10 +451,15 @@
<message> <message>
<location filename="../../src/TopRoomBar.cpp" line="+79"/> <location filename="../../src/TopRoomBar.cpp" line="+79"/>
<source>Room options</source> <source>Room options</source>
<translation type="unfinished"></translation> <translation>Raumoptionen</translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation>Erwähnungen</translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation>Benutzer einladen</translation> <translation>Benutzer einladen</translation>
</message> </message>
@ -459,15 +494,14 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> tippt</translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation>
<message> <numerusform>%1%2 tippt</numerusform>
<location line="+2"/> <numerusform>%1 und %2 tippen</numerusform>
<source> are typing</source> </translation>
<translation> tippen</translation>
</message> </message>
</context> </context>
<context> <context>
@ -475,13 +509,13 @@
<message> <message>
<location filename="../../src/UserInfoWidget.cpp" line="+87"/> <location filename="../../src/UserInfoWidget.cpp" line="+87"/>
<source>Logout</source> <source>Logout</source>
<translation type="unfinished"></translation> <translation>Abmelden</translation>
</message> </message>
</context> </context>
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation>Ins Benachrichtigungsfeld minimieren</translation> <translation>Ins Benachrichtigungsfeld minimieren</translation>
</message> </message>
@ -508,57 +542,62 @@
<message> <message>
<location line="+9"/> <location line="+9"/>
<source>Desktop notifications</source> <source>Desktop notifications</source>
<translation type="unfinished"></translation> <translation>Desktopbenachrichtigungen</translation>
</message> </message>
<message> <message>
<location line="+9"/> <location line="+9"/>
<source>Scale factor</source> <source>Scale factor</source>
<translation type="unfinished"></translation> <translation>Skalierungsfaktor</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+11"/>
<source>Font size</source> <source>Font size</source>
<translation type="unfinished"></translation> <translation>Schriftgröße</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation>Schriftart</translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation>Emoji Schriftart</translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation>Erscheinungsbild</translation> <translation>Erscheinungsbild</translation>
</message> </message>
<message> <message>
<location line="+27"/> <location line="+27"/>
<source>Device ID</source> <source>Device ID</source>
<translation type="unfinished"></translation> <translation>Geräte-ID</translation>
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>Device Fingerprint</source> <source>Device Fingerprint</source>
<translation type="unfinished"></translation> <translation>Gerätefingerabdruck</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+11"/>
<source>Session Keys</source> <source>Session Keys</source>
<translation type="unfinished"></translation> <translation>Sitzungsschlüssel</translation>
</message> </message>
<message> <message>
<location line="+4"/> <location line="+4"/>
<source>IMPORT</source> <source>IMPORT</source>
<translation type="unfinished"></translation> <translation>IMPORTIEREN</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>EXPORT</source> <source>EXPORT</source>
<translation type="unfinished"></translation> <translation>EXPORTIEREN</translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<source>ENCRYPTION</source> <source>ENCRYPTION</source>
<translation type="unfinished"></translation> <translation>VERSCHLÜSSELUNG</translation>
</message> </message>
<message> <message>
<location line="+4"/> <location line="+4"/>
@ -566,9 +605,9 @@
<translation>ALLGEMEINES</translation> <translation>ALLGEMEINES</translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation type="unfinished"></translation> <translation>Öffne Sessions Datei</translation>
</message> </message>
<message> <message>
<location line="+4"/> <location line="+4"/>
@ -582,34 +621,34 @@
<location line="+2"/> <location line="+2"/>
<location line="+2"/> <location line="+2"/>
<source>Error</source> <source>Error</source>
<translation type="unfinished"></translation> <translation>Feher</translation>
</message> </message>
<message> <message>
<location line="-73"/> <location line="-73"/>
<location line="+32"/> <location line="+32"/>
<source>File Password</source> <source>File Password</source>
<translation type="unfinished"></translation> <translation>Password für Datei</translation>
</message> </message>
<message> <message>
<location line="-31"/> <location line="-31"/>
<source>Enter the passphrase to decrypt the file:</source> <source>Enter the passphrase to decrypt the file:</source>
<translation type="unfinished"></translation> <translation>Bitte gib das Passwort zum Enschlüsseln der Datei ein:</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
<location line="+32"/> <location line="+32"/>
<source>The password cannot be empty</source> <source>The password cannot be empty</source>
<translation type="unfinished"></translation> <translation>Das Passwort darf nicht leer sein</translation>
</message> </message>
<message> <message>
<location line="-8"/> <location line="-8"/>
<source>Enter passphrase to encrypt your session keys:</source> <source>Enter passphrase to encrypt your session keys:</source>
<translation type="unfinished"></translation> <translation>Bitte gib das Passwort zum Verschlüsseln der Sitzungsschlüssel ein:</translation>
</message> </message>
<message> <message>
<location line="+14"/> <location line="+14"/>
<source>File to save the exported session keys</source> <source>File to save the exported session keys</source>
<translation type="unfinished"></translation> <translation>Datei zum Speichern der zu exportierenden Sitzungsschlüssel</translation>
</message> </message>
</context> </context>
<context> <context>
@ -617,12 +656,12 @@
<message> <message>
<location filename="../../src/WelcomePage.cpp" line="+46"/> <location filename="../../src/WelcomePage.cpp" line="+46"/>
<source>Welcome to nheko! The desktop client for the Matrix protocol.</source> <source>Welcome to nheko! The desktop client for the Matrix protocol.</source>
<translation>Willkommen bei nheko, dem Desktop-Client für das Matrix-Protokoll.</translation> <translation>Willkommen bei nheko! Ein Desktop-Client für das Matrix-Protokoll.</translation>
</message> </message>
<message> <message>
<location line="+1"/> <location line="+1"/>
<source>Enjoy your stay!</source> <source>Enjoy your stay!</source>
<translation>Genieße deinen Aufenthalt!</translation> <translation>Viel Vergnügen!</translation>
</message> </message>
<message> <message>
<location line="+23"/> <location line="+23"/>
@ -635,22 +674,30 @@
<translation>ANMELDEN</translation> <translation>ANMELDEN</translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation>Gestern</translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
<location filename="../../src/dialogs/CreateRoom.cpp" line="+36"/> <location filename="../../src/dialogs/CreateRoom.cpp" line="+36"/>
<source>Create room</source> <source>Create room</source>
<translation type="unfinished"></translation> <translation>Raum erstellen</translation>
</message> </message>
<message> <message>
<location line="+2"/> <location line="+2"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+10"/> <location line="+10"/>
<source>Name</source> <source>Name</source>
<translation>Titel</translation> <translation>Raumname</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
@ -660,7 +707,7 @@
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>Alias</source> <source>Alias</source>
<translation>Alias</translation> <translation>Raumalias</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
@ -683,7 +730,7 @@
<message> <message>
<location filename="../../src/dialogs/InviteUsers.cpp" line="+41"/> <location filename="../../src/dialogs/InviteUsers.cpp" line="+41"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
@ -696,12 +743,12 @@
<message> <message>
<location filename="../../src/dialogs/JoinRoom.cpp" line="+30"/> <location filename="../../src/dialogs/JoinRoom.cpp" line="+30"/>
<source>Join</source> <source>Join</source>
<translation type="unfinished"></translation> <translation>Betreten</translation>
</message> </message>
<message> <message>
<location line="+2"/> <location line="+2"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+7"/> <location line="+7"/>
@ -714,7 +761,7 @@
<message> <message>
<location filename="../../src/dialogs/LeaveRoom.cpp" line="+31"/> <location filename="../../src/dialogs/LeaveRoom.cpp" line="+31"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
@ -727,7 +774,7 @@
<message> <message>
<location filename="../../src/dialogs/Logout.cpp" line="+47"/> <location filename="../../src/dialogs/Logout.cpp" line="+47"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
@ -762,12 +809,12 @@ Medien-Größe: %2
<message> <message>
<location filename="../../src/dialogs/ReCaptcha.cpp" line="+31"/> <location filename="../../src/dialogs/ReCaptcha.cpp" line="+31"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished">Abbrechen</translation> <translation>Abbrechen</translation>
</message> </message>
<message> <message>
<location line="+1"/> <location line="+1"/>
<source>Confirm</source> <source>Confirm</source>
<translation type="unfinished"></translation> <translation>Bestätigen</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+11"/>
@ -778,19 +825,27 @@ Medien-Größe: %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation>Lesebestätigungen</translation> <translation>Lesebestätigungen</translation>
</message> </message>
<message> <message>
<location line="+4"/> <location line="+4"/>
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation>Schließen</translation>
</message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message>
<location line="-44"/>
<source>Today %1</source>
<translation>Heute %1</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+2"/>
<source>ESC</source> <source>Yesterday %1</source>
<translation type="unfinished"></translation> <translation>Gestern %1</translation>
</message> </message>
</context> </context>
<context> <context>
@ -798,22 +853,22 @@ Medien-Größe: %2
<message> <message>
<location filename="../../src/dialogs/RoomSettings.cpp" line="+113"/> <location filename="../../src/dialogs/RoomSettings.cpp" line="+113"/>
<source>Settings</source> <source>Settings</source>
<translation type="unfinished">Einstellungen</translation> <translation>Einstellungen</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>Info</source> <source>Info</source>
<translation type="unfinished"></translation> <translation>Informationen</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+11"/>
<source>Internal ID</source> <source>Internal ID</source>
<translation type="unfinished"></translation> <translation>interne ID</translation>
</message> </message>
<message> <message>
<location line="+10"/> <location line="+10"/>
<source>Room Version</source> <source>Room Version</source>
<translation type="unfinished"></translation> <translation>Raumversion</translation>
</message> </message>
<message> <message>
<location line="+4"/> <location line="+4"/>
@ -858,73 +913,81 @@ Medien-Größe: %2
<message> <message>
<location line="+50"/> <location line="+50"/>
<source>Encryption</source> <source>Encryption</source>
<translation type="unfinished"></translation> <translation>Verschlüsselung</translation>
</message> </message>
<message> <message>
<location line="+8"/> <location line="+8"/>
<source>End-to-End Encryption</source> <source>End-to-End Encryption</source>
<translation type="unfinished"></translation> <translation>Ende-zu-Ende Verschlüsselung</translation>
</message> </message>
<message> <message>
<location line="+1"/> <location line="+1"/>
<source>Encryption is currently experimental and things might break unexpectedly. &lt;br&gt;Please take note that it can&apos;t be disabled afterwards.</source> <source>Encryption is currently experimental and things might break unexpectedly. &lt;br&gt;Please take note that it can&apos;t be disabled afterwards.</source>
<translation type="unfinished"></translation> <translation>Verschlüsselung befindet sich momentan in einem experimentellen Stadium, unerwartete Fehler können auftreten. &lt;br&gt;Sie kann anschließend nicht wieder deaktiviert werden.</translation>
</message> </message>
<message> <message>
<location line="+27"/> <location line="+27"/>
<source>Respond to key requests</source> <source>Respond to key requests</source>
<translation type="unfinished"></translation> <translation>Schlüsselnfrage beantworten</translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+3"/>
<source>Whether or not the client should respond automatically with the session keys <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 upon request. Use with caution, this is a temporary measure to test the
E2E implementation until device verification is completed.</source> E2E implementation until device verification is completed.</source>
<translation type="unfinished"></translation> <translation>Ob nheko automatisch auf Anfragen mit Sessionschlüsseln antworten soll, oder nicht. Bitte mit Vorsicht nutzen, da dies eine temporäre Massnahme ist. Sie dient dem Test von E2E Verschlüsselung, bis die Geräteverifikation fertig gestellt ist.</translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location line="+53"/> <location line="+53"/>
<source>%n member(s)</source> <source>%n member(s)</source>
<translation type="unfinished"> <translation>
<numerusform></numerusform> <numerusform>%n Teilnehmer</numerusform>
<numerusform></numerusform> <numerusform>%n Teilnehmer</numerusform>
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation type="unfinished"></translation> <translation>Aktivierung der Verschlüsselung fehlgeschlagen: %1</translation>
</message> </message>
<message> <message>
<location line="+149"/> <location line="+149"/>
<source>Select an avatar</source> <source>Select an avatar</source>
<translation type="unfinished"></translation> <translation>Wähle einen Avatar</translation>
</message> </message>
<message> <message>
<location line="+0"/> <location line="+0"/>
<source>All Files (*)</source> <source>All Files (*)</source>
<translation type="unfinished">Alle Dateien (*)</translation> <translation>Alle Dateien (*)</translation>
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation type="unfinished"></translation> <translation>Die ausgewählte Datei ist kein Bild</translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation type="unfinished"></translation> <translation>Fehler beim Lesen der DateI: %1</translation>
</message> </message>
<message> <message>
<location line="+35"/> <location line="+35"/>
<location line="+20"/> <location line="+20"/>
<source>Failed to upload image: %s</source> <source>Failed to upload image: %s</source>
<translation type="unfinished"></translation> <translation>Hochladen der Bilddatei fehlgeschlagen: %s</translation>
</message>
</context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation>Dieser Raum</translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation>Alle Räume</translation>
</message> </message>
</context> </context>
<context> <context>
@ -932,32 +995,27 @@ Medien-Größe: %2
<message> <message>
<location filename="../../src/dialogs/UserProfile.cpp" line="+63"/> <location filename="../../src/dialogs/UserProfile.cpp" line="+63"/>
<source>Ban the user from the room</source> <source>Ban the user from the room</source>
<translation type="unfinished"></translation> <translation>Banne den Nutzer aus diesem Raum</translation>
</message> </message>
<message> <message>
<location line="+9"/> <location line="+9"/>
<source>Ignore messages from this user</source> <source>Ignore messages from this user</source>
<translation type="unfinished"></translation> <translation>Nachrichten von diesem Nutzer ignorieren</translation>
</message> </message>
<message> <message>
<location line="+9"/> <location line="+9"/>
<source>Kick the user from the room</source> <source>Kick the user from the room</source>
<translation type="unfinished"></translation> <translation>Entferne diesen Nutzer aus dem Raum</translation>
</message> </message>
<message> <message>
<location line="+9"/> <location line="+9"/>
<source>Start a conversation</source> <source>Start a conversation</source>
<translation type="unfinished"></translation> <translation>Gespräch beginnen</translation>
</message> </message>
<message> <message>
<location line="+57"/> <location line="+57"/>
<source>Devices</source> <source>Devices</source>
<translation type="unfinished"></translation> <translation>Geräte</translation>
</message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -1003,4 +1061,94 @@ Medien-Größe: %2
<translation>Flaggen</translation> <translation>Flaggen</translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation>%1 einen Audioclip</translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation>%1 ein Bild</translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation>%1 eine Datei</translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation>%1 einen Videoclip</translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation>%1 einen Sticker</translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation>1% eine Benachrichtigung</translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation>1% eine verschüsselte Nachricht</translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation>Du</translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation>Unbekannter Nachrichtentyp</translation>
</message>
</context>
</TS> </TS>

View file

@ -4,7 +4,7 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation>Αποθήκευση</translation> <translation>Αποθήκευση</translation>
</message> </message>
@ -12,7 +12,7 @@
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -32,7 +32,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -42,7 +42,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation>Αποθήκευση</translation> <translation>Αποθήκευση</translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation>Αποθήκευση Εικόνας</translation> <translation>Αποθήκευση Εικόνας</translation>
</message> </message>
@ -205,8 +205,8 @@
<translation>Μέλη</translation> <translation>Μέλη</translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -277,7 +277,7 @@
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -285,12 +285,12 @@
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation>Βγές</translation> <translation>Βγές</translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation>Αποδοχή</translation> <translation>Αποδοχή</translation>
</message> </message>
@ -331,7 +331,7 @@
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -354,13 +354,13 @@
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>Γράψε ένα μήνυμα...</translation> <translation>Γράψε ένα μήνυμα...</translation>
</message> </message>
@ -415,6 +415,36 @@
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>TopRoomBar</name> <name>TopRoomBar</name>
@ -424,7 +454,12 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation>Προσκάλεσε χρήστες</translation> <translation>Προσκάλεσε χρήστες</translation>
</message> </message>
@ -459,15 +494,14 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> πληκτρολογεί</translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation type="unfinished">
<message> <numerusform></numerusform>
<location line="+2"/> <numerusform></numerusform>
<source> are typing</source> </translation>
<translation> πληκτρολογούν</translation>
</message> </message>
</context> </context>
<context> <context>
@ -481,7 +515,7 @@
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation>Ελαχιστοποίηση</translation> <translation>Ελαχιστοποίηση</translation>
</message> </message>
@ -521,12 +555,17 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation>Φόντο</translation> <translation>Φόντο</translation>
</message> </message>
@ -566,7 +605,7 @@
<translation>ΓΕΝΙΚΑ</translation> <translation>ΓΕΝΙΚΑ</translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -635,6 +674,14 @@
<translation>ΕΙΣΟΔΟΣ</translation> <translation>ΕΙΣΟΔΟΣ</translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
@ -776,7 +823,7 @@ Media size: %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -785,9 +832,17 @@ Media size: %2
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message> <message>
<location line="+11"/> <location line="-44"/>
<source>ESC</source> <source>Today %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yesterday %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -889,12 +944,7 @@ Media size: %2
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -910,12 +960,12 @@ Media size: %2
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
@ -925,6 +975,19 @@ Media size: %2
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::UserProfile</name> <name>dialogs::UserProfile</name>
<message> <message>
@ -952,11 +1015,6 @@ Media size: %2
<source>Devices</source> <source>Devices</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>emoji::Panel</name> <name>emoji::Panel</name>
@ -1001,4 +1059,94 @@ Media size: %2
<translation>Σημαίες</translation> <translation>Σημαίες</translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS> </TS>

File diff suppressed because it is too large Load diff

1156
resources/langs/nheko_fi.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation>Enregistrer le fichier</translation> <translation>Enregistrer le fichier</translation>
</message> </message>
@ -12,7 +12,7 @@
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -32,7 +32,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -42,7 +42,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation>Enregistrer le fichier</translation> <translation>Enregistrer le fichier</translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation>Enregistrer l&apos;image</translation> <translation>Enregistrer l&apos;image</translation>
</message> </message>
@ -205,8 +205,8 @@
<translation>Membres du salon</translation> <translation>Membres du salon</translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -278,7 +278,7 @@
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -286,12 +286,12 @@
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation>Quitter le salon</translation> <translation>Quitter le salon</translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation>Accepter</translation> <translation>Accepter</translation>
</message> </message>
@ -332,7 +332,7 @@
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -355,13 +355,13 @@
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>Écrivez un message...</translation> <translation>Écrivez un message...</translation>
</message> </message>
@ -416,6 +416,36 @@
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>TopRoomBar</name> <name>TopRoomBar</name>
@ -425,7 +455,12 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation>Inviter des utilisateurs</translation> <translation>Inviter des utilisateurs</translation>
</message> </message>
@ -460,15 +495,14 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> est en train d&apos;écrire</translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation type="unfinished">
<message> <numerusform></numerusform>
<location line="+2"/> <numerusform></numerusform>
<source> are typing</source> </translation>
<translation> sont en train d&apos;écrire</translation>
</message> </message>
</context> </context>
<context> <context>
@ -482,7 +516,7 @@
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation>Réduire à la barre des tâches</translation> <translation>Réduire à la barre des tâches</translation>
</message> </message>
@ -522,12 +556,17 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation>Thème</translation> <translation>Thème</translation>
</message> </message>
@ -567,7 +606,7 @@
<translation>GÉNÉRAL</translation> <translation>GÉNÉRAL</translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -636,6 +675,14 @@
<translation>CONNEXION</translation> <translation>CONNEXION</translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
@ -779,7 +826,7 @@ Taille du média : %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation>Accusés de lecture</translation> <translation>Accusés de lecture</translation>
</message> </message>
@ -788,9 +835,17 @@ Taille du média : %2
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message> <message>
<location line="+11"/> <location line="-44"/>
<source>ESC</source> <source>Today %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yesterday %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -892,12 +947,7 @@ Taille du média : %2
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -913,12 +963,12 @@ Taille du média : %2
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
@ -928,6 +978,19 @@ Taille du média : %2
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::UserProfile</name> <name>dialogs::UserProfile</name>
<message> <message>
@ -955,11 +1018,6 @@ Taille du média : %2
<source>Devices</source> <source>Devices</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>emoji::Panel</name> <name>emoji::Panel</name>
@ -1004,4 +1062,94 @@ Taille du média : %2
<translation>Drapeaux</translation> <translation>Drapeaux</translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS> </TS>

View file

@ -4,7 +4,7 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation>Bestand opslaan</translation> <translation>Bestand opslaan</translation>
</message> </message>
@ -12,7 +12,7 @@
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -32,7 +32,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -42,7 +42,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation>Bestand opslaan</translation> <translation>Bestand opslaan</translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation>Afbeelding opslaan</translation> <translation>Afbeelding opslaan</translation>
</message> </message>
@ -205,8 +205,8 @@
<translation>Kamerleden</translation> <translation>Kamerleden</translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -277,7 +277,7 @@
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -285,12 +285,12 @@
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation>Kamer verlaten</translation> <translation>Kamer verlaten</translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation>Accepteren</translation> <translation>Accepteren</translation>
</message> </message>
@ -331,7 +331,7 @@
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -354,13 +354,13 @@
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>Typ een bericht...</translation> <translation>Typ een bericht...</translation>
</message> </message>
@ -415,6 +415,36 @@
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>TopRoomBar</name> <name>TopRoomBar</name>
@ -424,7 +454,12 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation>Gebruikers uitnodigen</translation> <translation>Gebruikers uitnodigen</translation>
</message> </message>
@ -459,15 +494,14 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> is aan het typen</translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation type="unfinished">
<message> <numerusform></numerusform>
<location line="+2"/> <numerusform></numerusform>
<source> are typing</source> </translation>
<translation> zijn aan het typen</translation>
</message> </message>
</context> </context>
<context> <context>
@ -481,7 +515,7 @@
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation>Minimaliseren naar systeemvak</translation> <translation>Minimaliseren naar systeemvak</translation>
</message> </message>
@ -521,12 +555,17 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation>Thema</translation> <translation>Thema</translation>
</message> </message>
@ -566,7 +605,7 @@
<translation>ALGEMEEN</translation> <translation>ALGEMEEN</translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -635,6 +674,14 @@
<translation>INLOGGEN</translation> <translation>INLOGGEN</translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
@ -778,7 +825,7 @@ Mediagrootte: %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation>Leesbevestigingen</translation> <translation>Leesbevestigingen</translation>
</message> </message>
@ -787,9 +834,17 @@ Mediagrootte: %2
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message> <message>
<location line="+11"/> <location line="-44"/>
<source>ESC</source> <source>Today %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yesterday %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -891,12 +946,7 @@ Mediagrootte: %2
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -912,12 +962,12 @@ Mediagrootte: %2
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
@ -927,6 +977,19 @@ Mediagrootte: %2
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::UserProfile</name> <name>dialogs::UserProfile</name>
<message> <message>
@ -954,11 +1017,6 @@ Mediagrootte: %2
<source>Devices</source> <source>Devices</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>emoji::Panel</name> <name>emoji::Panel</name>
@ -1003,4 +1061,94 @@ Mediagrootte: %2
<translation>Vlaggen</translation> <translation>Vlaggen</translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS> </TS>

View file

@ -4,7 +4,7 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation>Zapisz plik</translation> <translation>Zapisz plik</translation>
</message> </message>
@ -12,7 +12,7 @@
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation>Nie udało się wysłać obrazu. Spróbuj ponownie.</translation> <translation>Nie udało się wysłać obrazu. Spróbuj ponownie.</translation>
</message> </message>
@ -32,7 +32,7 @@
<translation>Nie udało się wysłać filmu. Spróbuj ponownie.</translation> <translation>Nie udało się wysłać filmu. Spróbuj ponownie.</translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation>Nie udało się przywrócić konta OLM. Spróbuj zalogować się ponownie.</translation> <translation>Nie udało się przywrócić konta OLM. Spróbuj zalogować się ponownie.</translation>
</message> </message>
@ -42,7 +42,7 @@
<translation>Nie udało się przywrócić zapisanych danych. Spróbuj zalogować się ponownie.</translation> <translation>Nie udało się przywrócić zapisanych danych. Spróbuj zalogować się ponownie.</translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation>Zapisz plik</translation> <translation>Zapisz plik</translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation>Zapisz obraz</translation> <translation>Zapisz obraz</translation>
</message> </message>
@ -205,8 +205,8 @@
<translation>Członkowie pokoju</translation> <translation>Członkowie pokoju</translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -277,7 +277,7 @@
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -285,12 +285,12 @@
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation>Opuść pokój</translation> <translation>Opuść pokój</translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation>Akceptuj</translation> <translation>Akceptuj</translation>
</message> </message>
@ -331,7 +331,7 @@
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation>Szyfrowana</translation> <translation>Szyfrowana</translation>
</message> </message>
@ -354,13 +354,13 @@
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation>Wyślij plik</translation> <translation>Wyślij plik</translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>Napisz wiadomość</translation> <translation>Napisz wiadomość</translation>
</message> </message>
@ -415,6 +415,36 @@
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation>Szyfrowanie jest włączone</translation> <translation>Szyfrowanie jest włączone</translation>
</message> </message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>TopRoomBar</name> <name>TopRoomBar</name>
@ -424,7 +454,12 @@
<translation>Ustawienia pokoju</translation> <translation>Ustawienia pokoju</translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation>Zaproś użytkowników</translation> <translation>Zaproś użytkowników</translation>
</message> </message>
@ -459,15 +494,15 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> pisze</translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation type="unfinished">
<message> <numerusform></numerusform>
<location line="+2"/> <numerusform></numerusform>
<source> are typing</source> <numerusform></numerusform>
<translation> piszą</translation> </translation>
</message> </message>
</context> </context>
<context> <context>
@ -481,7 +516,7 @@
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation>Zminimalizuj do paska zadań</translation> <translation>Zminimalizuj do paska zadań</translation>
</message> </message>
@ -521,12 +556,17 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation>Motyw</translation> <translation>Motyw</translation>
</message> </message>
@ -566,7 +606,7 @@
<translation>OGÓLNE</translation> <translation>OGÓLNE</translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -635,6 +675,14 @@
<translation>ZALOGUJ SIĘ</translation> <translation>ZALOGUJ SIĘ</translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
@ -778,7 +826,7 @@ Rozmiar multimediów: %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation>Potwierdzenia przeczytania</translation> <translation>Potwierdzenia przeczytania</translation>
</message> </message>
@ -787,9 +835,17 @@ Rozmiar multimediów: %2
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message> <message>
<location line="+11"/> <location line="-44"/>
<source>ESC</source> <source>Today %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yesterday %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -894,12 +950,7 @@ Rozmiar multimediów: %2
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation>Nie udało się włączyć szyfrowania: %1</translation> <translation>Nie udało się włączyć szyfrowania: %1</translation>
</message> </message>
@ -915,13 +966,13 @@ Rozmiar multimediów: %2
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation>Wybrany plik multimedialny nie jest obrazem</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation>Błąd odczytywania pliku: %1</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+35"/> <location line="+35"/>
@ -930,6 +981,19 @@ Rozmiar multimediów: %2
<translation>Nie udało się wysłać obrazu: %s</translation> <translation>Nie udało się wysłać obrazu: %s</translation>
</message> </message>
</context> </context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::UserProfile</name> <name>dialogs::UserProfile</name>
<message> <message>
@ -957,11 +1021,6 @@ Rozmiar multimediów: %2
<source>Devices</source> <source>Devices</source>
<translation>Urządzenia</translation> <translation>Urządzenia</translation>
</message> </message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>emoji::Panel</name> <name>emoji::Panel</name>
@ -1006,4 +1065,94 @@ Rozmiar multimediów: %2
<translation>Flagi</translation> <translation>Flagi</translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS> </TS>

View file

@ -4,7 +4,7 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation>Сохранить файл</translation> <translation>Сохранить файл</translation>
</message> </message>
@ -12,7 +12,7 @@
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation>Не удалось загрузить изображение. Пожалуйста, попробуйте еще раз.</translation> <translation>Не удалось загрузить изображение. Пожалуйста, попробуйте еще раз.</translation>
</message> </message>
@ -32,7 +32,7 @@
<translation>Не удалось загрузить видео. Пожалуйста, попробуйте еще раз.</translation> <translation>Не удалось загрузить видео. Пожалуйста, попробуйте еще раз.</translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation>Не удалось восстановить учетную запись OLM. Пожалуйста, войдите снова.</translation> <translation>Не удалось восстановить учетную запись OLM. Пожалуйста, войдите снова.</translation>
</message> </message>
@ -42,7 +42,7 @@
<translation>Не удалось восстановить сохраненные данные. Пожалуйста, войдите снова.</translation> <translation>Не удалось восстановить сохраненные данные. Пожалуйста, войдите снова.</translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation>Не удалось настроить ключи шифрования. Ответ сервера:%1 %2. Пожалуйста, попробуйте позже.</translation> <translation>Не удалось настроить ключи шифрования. Ответ сервера:%1 %2. Пожалуйста, попробуйте позже.</translation>
</message> </message>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation>Сохранить файл</translation> <translation>Сохранить файл</translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation>Сохранить изображение</translation> <translation>Сохранить изображение</translation>
</message> </message>
@ -205,9 +205,9 @@
<translation>Участники комнаты</translation> <translation>Участники комнаты</translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -277,7 +277,7 @@
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -285,12 +285,12 @@
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation>Покинуть комнату</translation> <translation>Покинуть комнату</translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation>Принять</translation> <translation>Принять</translation>
</message> </message>
@ -331,7 +331,7 @@
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation>Зашифровано</translation> <translation>Зашифровано</translation>
</message> </message>
@ -354,13 +354,13 @@
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation>Отправить файл</translation> <translation>Отправить файл</translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>Написать сообщение...</translation> <translation>Написать сообщение...</translation>
</message> </message>
@ -415,6 +415,36 @@
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation>Шифрование включено</translation> <translation>Шифрование включено</translation>
</message> </message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>TopRoomBar</name> <name>TopRoomBar</name>
@ -424,7 +454,12 @@
<translation>Настройки комнаты</translation> <translation>Настройки комнаты</translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation>Пригласить пользователей</translation> <translation>Пригласить пользователей</translation>
</message> </message>
@ -459,15 +494,15 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> печатает</translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation type="unfinished">
<message> <numerusform></numerusform>
<location line="+2"/> <numerusform></numerusform>
<source> are typing</source> <numerusform></numerusform>
<translation> печатают</translation> </translation>
</message> </message>
</context> </context>
<context> <context>
@ -481,7 +516,7 @@
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation>Сворачивать в системную панель</translation> <translation>Сворачивать в системную панель</translation>
</message> </message>
@ -521,12 +556,17 @@
<translation>Размер шрифта</translation> <translation>Размер шрифта</translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation>Тема</translation> <translation>Тема</translation>
</message> </message>
@ -566,7 +606,7 @@
<translation>ГЛАВНОЕ</translation> <translation>ГЛАВНОЕ</translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation>Открыть файл сеансов</translation> <translation>Открыть файл сеансов</translation>
</message> </message>
@ -636,6 +676,14 @@
<translation>ВХОД</translation> <translation>ВХОД</translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
@ -779,7 +827,7 @@ Media size: %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation>Подтверждать прочтение</translation> <translation>Подтверждать прочтение</translation>
</message> </message>
@ -788,10 +836,18 @@ Media size: %2
<source>Close</source> <source>Close</source>
<translation>Закрыть</translation> <translation>Закрыть</translation>
</message> </message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message> <message>
<location line="+11"/> <location line="-44"/>
<source>ESC</source> <source>Today %1</source>
<translation></translation> <translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yesterday %1</source>
<translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -893,12 +949,7 @@ Media size: %2
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation>Не удалось включить шифрование: %1</translation> <translation>Не удалось включить шифрование: %1</translation>
</message> </message>
@ -914,13 +965,13 @@ Media size: %2
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation>Выбранное медия не является изображением</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation>Ошибка при чтении медия: %1</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+35"/> <location line="+35"/>
@ -929,6 +980,19 @@ Media size: %2
<translation>Не удалось загрузить изображение: %s</translation> <translation>Не удалось загрузить изображение: %s</translation>
</message> </message>
</context> </context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::UserProfile</name> <name>dialogs::UserProfile</name>
<message> <message>
@ -956,11 +1020,6 @@ Media size: %2
<source>Devices</source> <source>Devices</source>
<translation>Устройства</translation> <translation>Устройства</translation>
</message> </message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation></translation>
</message>
</context> </context>
<context> <context>
<name>emoji::Panel</name> <name>emoji::Panel</name>
@ -1005,4 +1064,94 @@ Media size: %2
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS> </TS>

View file

@ -4,7 +4,7 @@
<context> <context>
<name>AudioItem</name> <name>AudioItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/AudioItem.cpp" line="+117"/> <location filename="../../src/timeline/widgets/AudioItem.cpp" line="+118"/>
<source>Save File</source> <source>Save File</source>
<translation></translation> <translation></translation>
</message> </message>
@ -12,7 +12,7 @@
<context> <context>
<name>ChatPage</name> <name>ChatPage</name>
<message> <message>
<location filename="../../src/ChatPage.cpp" line="+309"/> <location filename="../../src/ChatPage.cpp" line="+330"/>
<source>Failed to upload image. Please try again.</source> <source>Failed to upload image. Please try again.</source>
<translation></translation> <translation></translation>
</message> </message>
@ -32,7 +32,7 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+376"/> <location line="+380"/>
<source>Failed to restore OLM account. Please login again.</source> <source>Failed to restore OLM account. Please login again.</source>
<translation> OLM </translation> <translation> OLM </translation>
</message> </message>
@ -42,7 +42,7 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+169"/> <location line="+198"/>
<source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -118,7 +118,7 @@
<context> <context>
<name>FileItem</name> <name>FileItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/FileItem.cpp" line="+106"/> <location filename="../../src/timeline/widgets/FileItem.cpp" line="+107"/>
<source>Save File</source> <source>Save File</source>
<translation></translation> <translation></translation>
</message> </message>
@ -126,7 +126,7 @@
<context> <context>
<name>ImageItem</name> <name>ImageItem</name>
<message> <message>
<location filename="../../src/timeline/widgets/ImageItem.cpp" line="+238"/> <location filename="../../src/timeline/widgets/ImageItem.cpp" line="+241"/>
<source>Save image</source> <source>Save image</source>
<translation></translation> <translation></translation>
</message> </message>
@ -205,8 +205,8 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+4"/>
<source>ESC</source> <source>OK</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -277,7 +277,7 @@
<context> <context>
<name>RoomInfo</name> <name>RoomInfo</name>
<message> <message>
<location filename="../../src/Cache.cpp" line="+2204"/> <location filename="../../src/Cache.cpp" line="+2205"/>
<source>no version stored</source> <source>no version stored</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -285,12 +285,12 @@
<context> <context>
<name>RoomInfoListItem</name> <name>RoomInfoListItem</name>
<message> <message>
<location filename="../../src/RoomInfoListItem.cpp" line="+92"/> <location filename="../../src/RoomInfoListItem.cpp" line="+93"/>
<source>Leave room</source> <source>Leave room</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+174"/> <location line="+181"/>
<source>Accept</source> <source>Accept</source>
<translation></translation> <translation></translation>
</message> </message>
@ -331,7 +331,7 @@
<context> <context>
<name>StatusIndicator</name> <name>StatusIndicator</name>
<message> <message>
<location filename="../../src/timeline/TimelineItem.cpp" line="+106"/> <location filename="../../src/timeline/TimelineItem.cpp" line="+107"/>
<source>Encrypted</source> <source>Encrypted</source>
<translation></translation> <translation></translation>
</message> </message>
@ -354,13 +354,13 @@
<context> <context>
<name>TextInputWidget</name> <name>TextInputWidget</name>
<message> <message>
<location filename="../../src/TextInputWidget.cpp" line="+506"/> <location filename="../../src/TextInputWidget.cpp" line="+507"/>
<source>Send a file</source> <source>Send a file</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+13"/> <location line="+13"/>
<location filename="../../src/TextInputWidget.h" line="+168"/> <location filename="../../src/TextInputWidget.h" line="+164"/>
<source>Write a message...</source> <source>Write a message...</source>
<translation>...</translation> <translation>...</translation>
</message> </message>
@ -415,6 +415,36 @@
<source>Encryption is enabled</source> <source>Encryption is enabled</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location line="+65"/>
<source>-- Encrypted Event (No keys found for decryption) --</source>
<comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+15"/>
<source>-- Decryption Error (failed to communicate with DB) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed when trying to lookup the session.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+19"/>
<source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+12"/>
<source>-- Decryption Error (%1) --</source>
<comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+27"/>
<source>-- Encrypted Event (Unknown event type) --</source>
<comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet</comment>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>TopRoomBar</name> <name>TopRoomBar</name>
@ -424,7 +454,12 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+28"/> <location line="+5"/>
<source>Mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+34"/>
<source>Invite users</source> <source>Invite users</source>
<translation></translation> <translation></translation>
</message> </message>
@ -459,15 +494,13 @@
</context> </context>
<context> <context>
<name>TypingDisplay</name> <name>TypingDisplay</name>
<message> <message numerus="yes">
<location filename="../../src/TypingDisplay.cpp" line="+45"/> <location filename="../../src/TypingDisplay.cpp" line="+37"/>
<source> is typing</source> <source>%1 and %2 are typing</source>
<translation> </translation> <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment>
</message> <translation type="unfinished">
<message> <numerusform></numerusform>
<location line="+2"/> </translation>
<source> are typing</source>
<translation> </translation>
</message> </message>
</context> </context>
<context> <context>
@ -481,7 +514,7 @@
<context> <context>
<name>UserSettingsPage</name> <name>UserSettingsPage</name>
<message> <message>
<location filename="../../src/UserSettingsPage.cpp" line="+156"/> <location filename="../../src/UserSettingsPage.cpp" line="+166"/>
<source>Minimize to tray</source> <source>Minimize to tray</source>
<translation></translation> <translation></translation>
</message> </message>
@ -521,12 +554,17 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+11"/> <location line="+13"/>
<source>Font Family</source> <source>Font Family</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+17"/> <location line="+1"/>
<source>Emoji Font Famly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+33"/>
<source>Theme</source> <source>Theme</source>
<translation></translation> <translation></translation>
</message> </message>
@ -566,7 +604,7 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+150"/> <location line="+156"/>
<source>Open Sessions File</source> <source>Open Sessions File</source>
<translation></translation> <translation></translation>
</message> </message>
@ -635,6 +673,14 @@
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context>
<name>descriptiveTime</name>
<message>
<location filename="../../src/Utils.cpp" line="+104"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::CreateRoom</name> <name>dialogs::CreateRoom</name>
<message> <message>
@ -778,7 +824,7 @@ Media size: %2
<context> <context>
<name>dialogs::ReadReceipts</name> <name>dialogs::ReadReceipts</name>
<message> <message>
<location filename="../../src/dialogs/ReadReceipts.cpp" line="+119"/> <location filename="../../src/dialogs/ReadReceipts.cpp" line="+121"/>
<source>Read receipts</source> <source>Read receipts</source>
<translation></translation> <translation></translation>
</message> </message>
@ -787,9 +833,17 @@ Media size: %2
<source>Close</source> <source>Close</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>dialogs::ReceiptItem</name>
<message> <message>
<location line="+11"/> <location line="-44"/>
<source>ESC</source> <source>Today %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Yesterday %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -892,12 +946,7 @@ Media size: %2
</translation> </translation>
</message> </message>
<message> <message>
<location line="+71"/> <location line="+140"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+69"/>
<source>Failed to enable encryption: %1</source> <source>Failed to enable encryption: %1</source>
<translation>%1</translation> <translation>%1</translation>
</message> </message>
@ -913,13 +962,13 @@ Media size: %2
</message> </message>
<message> <message>
<location line="+12"/> <location line="+12"/>
<source>The selected media is not an image</source> <source>The selected file is not an image</source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+5"/> <location line="+5"/>
<source>Error while reading media: %1</source> <source>Error while reading file: %1</source>
<translation>%1</translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+35"/> <location line="+35"/>
@ -928,6 +977,19 @@ Media size: %2
<translation>%s</translation> <translation>%s</translation>
</message> </message>
</context> </context>
<context>
<name>dialogs::UserMentions</name>
<message>
<location filename="../../src/dialogs/UserMentions.cpp" line="+53"/>
<source>This Room</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>All Rooms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>dialogs::UserProfile</name> <name>dialogs::UserProfile</name>
<message> <message>
@ -955,11 +1017,6 @@ Media size: %2
<source>Devices</source> <source>Devices</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location line="+39"/>
<source>ESC</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>emoji::Panel</name> <name>emoji::Panel</name>
@ -1012,4 +1069,94 @@ Media size: %2
<translation>Flags</translation> <translation>Flags</translation>
</message> </message>
</context> </context>
<context>
<name>message-description sent:</name>
<message>
<location filename="../../src/Utils.h" line="+104"/>
<source>%1 an audio clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 an image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a video clip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a sticker</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>%1 a notification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>%1 an encrypted message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description:</name>
<message>
<location line="-26"/>
<source>sent</source>
<comment>For when someone else is the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>message-description: </name>
<message>
<location line="-2"/>
<source>sent</source>
<comment>For when you are the sender</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>utils</name>
<message>
<location filename="../../src/Utils.cpp" line="+46"/>
<location filename="../../src/Utils.h" line="+55"/>
<source>You</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+219"/>
<source>sent a file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an image.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent an audio file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>sent a video</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../src/Utils.h" line="-23"/>
<source>Unknown Message Type</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS> </TS>

View file

@ -24,6 +24,17 @@ TimelineView > * {
border: none; border: none;
} }
UserMentionsWidget,
UserMentionsWidget > * {
background-color: #202228;
border: none;
}
UserMentionsWidget > TimelineItem {
qproperty-backgroundColor: #202228;
qproperty-hoverColor: rgba(45, 49, 57, 120);
}
#scroll_widget { #scroll_widget {
background-color: #202228; background-color: #202228;
} }

View file

@ -24,6 +24,17 @@ TimelineView > * {
border: none; border: none;
} }
UserMentionsWidget,
UserMentionsWidget > * {
background-color: white;
border: none;
}
UserMentionsWidget > TimelineItem {
qproperty-backgroundColor: white;
qproperty-hoverColor: rgba(192, 193, 195, 120);
}
#scroll_widget { #scroll_widget {
background-color: white; background-color: white;
} }

View file

@ -12,6 +12,16 @@ TimelineView > * {
border: none; border: none;
} }
UserMentionsWidget,
UserMentionsWidget > * {
border: none;
}
UserMentionsWidget > TimelineItem {
qproperty-backgroundColor: palette(window);
qproperty-hoverColor: palette(base);
}
TextInputWidget { TextInputWidget {
border: none; border: none;
border-top: 1px solid palette(mid); border-top: 1px solid palette(mid);

View file

@ -16,30 +16,44 @@
*/ */
#include <QBuffer> #include <QBuffer>
#include <QPixmapCache>
#include <memory> #include <memory>
#include <unordered_map>
#include "AvatarProvider.h" #include "AvatarProvider.h"
#include "Cache.h" #include "Cache.h"
#include "Logging.h" #include "Logging.h"
#include "MatrixClient.h" #include "MatrixClient.h"
static QPixmapCache avatar_cache;
namespace AvatarProvider { namespace AvatarProvider {
void void
resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback callback) resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback callback)
{ {
const auto key = QString("%1 %2").arg(room_id).arg(user_id); avatar_cache.setCacheLimit(1024 * 1024);
const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
if (!Cache::AvatarUrls.contains(key) || !cache::client()) const auto cacheKey = avatarUrl + "_size_" + size;
if (!cache::client())
return; return;
if (avatarUrl.isEmpty()) if (avatarUrl.isEmpty())
return; return;
QPixmap pixmap;
if (avatar_cache.find(cacheKey, &pixmap)) {
nhlog::net()->info("cached pixmap {}", avatarUrl.toStdString());
callback(pixmap);
return;
}
auto data = cache::client()->image(avatarUrl); auto data = cache::client()->image(avatarUrl);
if (!data.isNull()) { if (!data.isNull()) {
callback(QImage::fromData(data)); pixmap.loadFromData(data);
avatar_cache.insert(cacheKey, pixmap);
nhlog::net()->info("loaded pixmap from disk cache {}", avatarUrl.toStdString());
callback(pixmap);
return; return;
} }
@ -47,7 +61,12 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
QObject::connect(proxy.get(), QObject::connect(proxy.get(),
&AvatarProxy::avatarDownloaded, &AvatarProxy::avatarDownloaded,
receiver, receiver,
[callback](const QByteArray &data) { callback(QImage::fromData(data)); }); [callback, cacheKey](const QByteArray &data) {
QPixmap pm;
pm.loadFromData(data);
avatar_cache.insert(cacheKey, pm);
callback(pm);
});
mtx::http::ThumbOpts opts; mtx::http::ThumbOpts opts;
opts.width = 256; opts.width = 256;
@ -67,8 +86,26 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
cache::client()->saveImage(opts.mxc_url, res); cache::client()->saveImage(opts.mxc_url, res);
auto data = QByteArray(res.data(), res.size()); nhlog::net()->info("downloaded pixmap {}", opts.mxc_url);
emit proxy->avatarDownloaded(data);
emit proxy->avatarDownloaded(QByteArray(res.data(), res.size()));
}); });
} }
void
resolve(const QString &room_id,
const QString &user_id,
int size,
QObject *receiver,
AvatarCallback callback)
{
const auto key = QString("%1 %2").arg(room_id).arg(user_id);
const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
const auto cacheKey = avatarUrl + "_size_" + size;
if (!Cache::AvatarUrls.contains(key) || !cache::client())
return;
resolve(avatarUrl, size, receiver, callback);
}
} }

View file

@ -17,7 +17,7 @@
#pragma once #pragma once
#include <QImage> #include <QPixmap>
#include <functional> #include <functional>
class AvatarProxy : public QObject class AvatarProxy : public QObject
@ -28,9 +28,15 @@ signals:
void avatarDownloaded(const QByteArray &data); void avatarDownloaded(const QByteArray &data);
}; };
using AvatarCallback = std::function<void(QImage)>; using AvatarCallback = std::function<void(QPixmap)>;
namespace AvatarProvider { namespace AvatarProvider {
void void
resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback cb); resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback cb);
void
resolve(const QString &room_id,
const QString &user_id,
int size,
QObject *receiver,
AvatarCallback cb);
} }

View file

@ -22,6 +22,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QFile> #include <QFile>
#include <QHash> #include <QHash>
#include <QMap>
#include <QSettings> #include <QSettings>
#include <QStandardPaths> #include <QStandardPaths>
@ -91,6 +92,7 @@ init(const QString &user_id)
qRegisterMetaType<RoomSearchResult>(); qRegisterMetaType<RoomSearchResult>();
qRegisterMetaType<RoomInfo>(); qRegisterMetaType<RoomInfo>();
qRegisterMetaType<QMap<QString, RoomInfo>>(); qRegisterMetaType<QMap<QString, RoomInfo>>();
qRegisterMetaType<QMap<QString, mtx::responses::Notifications>>();
qRegisterMetaType<std::map<QString, RoomInfo>>(); qRegisterMetaType<std::map<QString, RoomInfo>>();
qRegisterMetaType<std::map<QString, mtx::responses::Timeline>>(); qRegisterMetaType<std::map<QString, mtx::responses::Timeline>>();
@ -1232,6 +1234,27 @@ Cache::roomMessages()
return msgs; return msgs;
} }
QMap<QString, mtx::responses::Notifications>
Cache::getTimelineMentions()
{
// TODO: Should be read-only, but getMentionsDb will attempt to create a DB
// if it doesn't exist, throwing an error.
auto txn = lmdb::txn::begin(env_, nullptr);
QMap<QString, mtx::responses::Notifications> notifs;
auto room_ids = getRoomIds(txn);
for (const auto &room_id : room_ids) {
auto roomNotifs = getTimelineMentionsForRoom(txn, room_id);
notifs[QString::fromStdString(room_id)] = roomNotifs;
}
txn.commit();
return notifs;
}
mtx::responses::Timeline mtx::responses::Timeline
Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id) Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id)
{ {
@ -1807,10 +1830,7 @@ Cache::searchRooms(const std::string &query, std::uint8_t max_items)
std::vector<RoomSearchResult> results; std::vector<RoomSearchResult> results;
for (auto it = items.begin(); it != end; it++) { for (auto it = items.begin(); it != end; it++) {
results.push_back( results.push_back(RoomSearchResult{it->second.first, it->second.second});
RoomSearchResult{it->second.first,
it->second.second,
QImage::fromData(image(txn, it->second.second.avatar_url))});
} }
txn.commit(); txn.commit();
@ -1935,6 +1955,88 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
} }
} }
mtx::responses::Notifications
Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
{
auto db = getMentionsDb(txn, room_id);
if (db.size(txn) == 0) {
return mtx::responses::Notifications{};
}
mtx::responses::Notifications notif;
std::string event_id, msg;
auto cursor = lmdb::cursor::open(txn, db);
while (cursor.get(event_id, msg, MDB_NEXT)) {
auto obj = json::parse(msg);
if (obj.count("event") == 0)
continue;
mtx::responses::Notification notification;
mtx::responses::from_json(obj, notification);
notif.notifications.push_back(notification);
}
cursor.close();
std::reverse(notif.notifications.begin(), notif.notifications.end());
return notif;
}
//! Add all notifications containing a user mention to the db.
void
Cache::saveTimelineMentions(const mtx::responses::Notifications &res)
{
QMap<std::string, QList<mtx::responses::Notification>> notifsByRoom;
// Sort into room-specific 'buckets'
for (const auto &notif : res.notifications) {
json val = notif;
notifsByRoom[notif.room_id].push_back(notif);
}
auto txn = lmdb::txn::begin(env_);
// Insert the entire set of mentions for each room at a time.
QMap<std::string, QList<mtx::responses::Notification>>::const_iterator it =
notifsByRoom.constBegin();
auto end = notifsByRoom.constEnd();
while (it != end) {
nhlog::db()->debug("Storing notifications for " + it.key());
saveTimelineMentions(txn, it.key(), std::move(it.value()));
++it;
}
txn.commit();
}
void
Cache::saveTimelineMentions(lmdb::txn &txn,
const std::string &room_id,
const QList<mtx::responses::Notification> &res)
{
auto db = getMentionsDb(txn, room_id);
using namespace mtx::events;
using namespace mtx::events::state;
for (const auto &notif : res) {
const auto event_id = utils::event_id(notif.event);
// double check that we have the correct room_id...
if (room_id.compare(notif.room_id) != 0) {
return;
}
json obj = notif;
lmdb::dbi_put(txn, db, lmdb::val(event_id), lmdb::val(obj.dump()));
}
}
void void
Cache::markSentNotification(const std::string &event_id) Cache::markSentNotification(const std::string &event_id)
{ {

View file

@ -32,6 +32,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "Logging.h" #include "Logging.h"
#include "MatrixClient.h"
using mtx::events::state::JoinRule; using mtx::events::state::JoinRule;
@ -152,7 +153,6 @@ struct RoomSearchResult
{ {
std::string room_id; std::string room_id;
RoomInfo info; RoomInfo info;
QImage img;
}; };
Q_DECLARE_METATYPE(RoomSearchResult) Q_DECLARE_METATYPE(RoomSearchResult)
@ -323,6 +323,8 @@ public:
std::map<QString, mtx::responses::Timeline> roomMessages(); std::map<QString, mtx::responses::Timeline> roomMessages();
QMap<QString, mtx::responses::Notifications> getTimelineMentions();
//! Retrieve all the user ids from a room. //! Retrieve all the user ids from a room.
std::vector<std::string> roomMembers(const std::string &room_id); std::vector<std::string> roomMembers(const std::string &room_id);
@ -402,6 +404,9 @@ public:
//! Check if we have sent a desktop notification for the given event id. //! Check if we have sent a desktop notification for the given event id.
bool isNotificationSent(const std::string &event_id); bool isNotificationSent(const std::string &event_id);
//! Add all notifications containing a user mention to the db.
void saveTimelineMentions(const mtx::responses::Notifications &res);
//! Remove old unused data. //! Remove old unused data.
void deleteOldMessages(); void deleteOldMessages();
void deleteOldData() noexcept; void deleteOldData() noexcept;
@ -470,6 +475,15 @@ private:
lmdb::dbi &membersdb, lmdb::dbi &membersdb,
const mtx::responses::InvitedRoom &room); const mtx::responses::InvitedRoom &room);
//! Add a notification containing a user mention to the db.
void saveTimelineMentions(lmdb::txn &txn,
const std::string &room_id,
const QList<mtx::responses::Notification> &res);
//! Get timeline items that a user was mentions in for a given room
mtx::responses::Notifications getTimelineMentionsForRoom(lmdb::txn &txn,
const std::string &room_id);
QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb); QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
@ -660,6 +674,11 @@ private:
return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE); return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);
} }
lmdb::dbi getMentionsDb(lmdb::txn &txn, const std::string &room_id)
{
return lmdb::dbi::open(txn, std::string(room_id + "/mentions").c_str(), MDB_CREATE);
}
//! Retrieves or creates the database that stores the open OLM sessions between our device //! Retrieves or creates the database that stores the open OLM sessions between our device
//! and the given curve25519 key which represents another device. //! and the given curve25519 key which represents another device.
//! //!

View file

@ -35,7 +35,6 @@
#include "TopRoomBar.h" #include "TopRoomBar.h"
#include "TypingDisplay.h" #include "TypingDisplay.h"
#include "UserInfoWidget.h" #include "UserInfoWidget.h"
#include "UserMentionsWidget.h"
#include "UserSettingsPage.h" #include "UserSettingsPage.h"
#include "Utils.h" #include "Utils.h"
#include "ui/OverlayModal.h" #include "ui/OverlayModal.h"
@ -44,7 +43,7 @@
#include "notifications/Manager.h" #include "notifications/Manager.h"
#include "dialogs/ReadReceipts.h" #include "dialogs/ReadReceipts.h"
#include "dialogs/UserMentions.h" #include "popups/UserMentions.h"
#include "timeline/TimelineViewManager.h" #include "timeline/TimelineViewManager.h"
// TODO: Needs to be updated with an actual secret. // TODO: Needs to be updated with an actual secret.
@ -91,12 +90,11 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
connect(sidebarActions_, &SideBarActions::createRoom, this, &ChatPage::createRoom); connect(sidebarActions_, &SideBarActions::createRoom, this, &ChatPage::createRoom);
user_info_widget_ = new UserInfoWidget(sideBar_); user_info_widget_ = new UserInfoWidget(sideBar_);
// user_mentions_widget_ = new UserMentionsWidget(sideBar_); user_mentions_popup_ = new popups::UserMentions();
room_list_ = new RoomList(sideBar_); room_list_ = new RoomList(sideBar_);
connect(room_list_, &RoomList::joinRoom, this, &ChatPage::joinRoom); connect(room_list_, &RoomList::joinRoom, this, &ChatPage::joinRoom);
sideBarLayout_->addWidget(user_info_widget_); sideBarLayout_->addWidget(user_info_widget_);
// sideBarLayout_->addWidget(user_mentions_widget_);
sideBarLayout_->addWidget(room_list_); sideBarLayout_->addWidget(room_list_);
sideBarLayout_->addWidget(sidebarActions_); sideBarLayout_->addWidget(sidebarActions_);
@ -155,6 +153,10 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
}); });
connect(top_bar_, &TopRoomBar::mentionsClicked, this, [this](const QPoint &mentionsPos) { connect(top_bar_, &TopRoomBar::mentionsClicked, this, [this](const QPoint &mentionsPos) {
if (user_mentions_popup_->isVisible()) {
user_mentions_popup_->hide();
} else {
showNotificationsDialog(mentionsPos);
http::client()->notifications( http::client()->notifications(
1000, 1000,
"", "",
@ -162,7 +164,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
[this, mentionsPos](const mtx::responses::Notifications &res, [this, mentionsPos](const mtx::responses::Notifications &res,
mtx::http::RequestErr err) { mtx::http::RequestErr err) {
if (err) { if (err) {
nhlog::net()->warn("failed to retrieve notifications: {} ({})", nhlog::net()->warn(
"failed to retrieve notifications: {} ({})",
err->matrix_error.error, err->matrix_error.error,
static_cast<int>(err->status_code)); static_cast<int>(err->status_code));
return; return;
@ -170,6 +173,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
emit highlightedNotifsRetrieved(std::move(res), mentionsPos); emit highlightedNotifsRetrieved(std::move(res), mentionsPos);
}); });
}
}); });
connectivityTimer_.setInterval(CHECK_CONNECTIVITY_INTERVAL); connectivityTimer_.setInterval(CHECK_CONNECTIVITY_INTERVAL);
@ -519,8 +523,16 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom); connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom);
connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendDesktopNotifications); connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendDesktopNotifications);
connect( connect(this,
this, &ChatPage::highlightedNotifsRetrieved, this, &ChatPage::showNotificationsDialog); &ChatPage::highlightedNotifsRetrieved,
this,
[](const mtx::responses::Notifications &notif) {
try {
cache::client()->saveTimelineMentions(notif);
} catch (const lmdb::error &e) {
nhlog::db()->error("failed to save mentions: {}", e.what());
}
});
connect(communitiesList_, connect(communitiesList_,
&CommunitiesList::communityChanged, &CommunitiesList::communityChanged,
@ -559,6 +571,10 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
&ChatPage::initializeEmptyViews, &ChatPage::initializeEmptyViews,
view_manager_, view_manager_,
&TimelineViewManager::initWithMessages); &TimelineViewManager::initWithMessages);
connect(this,
&ChatPage::initializeMentions,
user_mentions_popup_,
&popups::UserMentions::initializeMentions);
connect(this, &ChatPage::syncUI, this, [this](const mtx::responses::Rooms &rooms) { connect(this, &ChatPage::syncUI, this, [this](const mtx::responses::Rooms &rooms) {
try { try {
room_list_->cleanupInvites(cache::client()->invites()); room_list_->cleanupInvites(cache::client()->invites());
@ -758,12 +774,12 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
} }
void void
ChatPage::updateTopBarAvatar(const QString &roomid, const QPixmap &img) ChatPage::updateTopBarAvatar(const QString &roomid, const QString &img)
{ {
if (current_room_ != roomid) if (current_room_ != roomid)
return; return;
top_bar_->updateRoomAvatar(img.toImage()); top_bar_->updateRoomAvatar(img);
} }
void void
@ -791,7 +807,7 @@ ChatPage::changeTopRoomInfo(const QString &room_id)
if (img.isNull()) if (img.isNull())
top_bar_->updateRoomAvatarFromName(name); top_bar_->updateRoomAvatarFromName(name);
else else
top_bar_->updateRoomAvatar(img); top_bar_->updateRoomAvatar(avatar_url);
} catch (const lmdb::error &e) { } catch (const lmdb::error &e) {
nhlog::ui()->error("failed to change top bar room info: {}", e.what()); nhlog::ui()->error("failed to change top bar room info: {}", e.what());
@ -831,6 +847,7 @@ ChatPage::loadStateFromCache()
emit initializeEmptyViews(cache::client()->roomMessages()); emit initializeEmptyViews(cache::client()->roomMessages());
emit initializeRoomList(cache::client()->roomInfo()); emit initializeRoomList(cache::client()->roomInfo());
emit initializeMentions(cache::client()->getTimelineMentions());
emit syncTags(cache::client()->roomInfo().toStdMap()); emit syncTags(cache::client()->roomInfo().toStdMap());
cache::client()->calculateRoomReadStatus(); cache::client()->calculateRoomReadStatus();
@ -987,32 +1004,15 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res)
} }
void void
ChatPage::showNotificationsDialog(const mtx::responses::Notifications &res, const QPoint &widgetPos) ChatPage::showNotificationsDialog(const QPoint &widgetPos)
{ {
// TODO: This should NOT BE A DIALOG. Make the TimelineView support auto notifDialog = user_mentions_popup_;
// creating a timeline view from notifications (similarly to how it can show history views)
auto notifDialog = new dialogs::UserMentions();
for (const auto &item : res.notifications) {
const auto event_id = QString::fromStdString(utils::event_id(item.event));
try {
const auto room_id = QString::fromStdString(item.room_id);
const auto user_id = utils::event_sender(item.event);
const auto body = utils::event_body(item.event);
notifDialog->pushItem(event_id, user_id, body, room_id);
} catch (const lmdb::error &e) {
nhlog::db()->warn("error while sending desktop notification: {}", e.what());
}
}
notifDialog->setGeometry( notifDialog->setGeometry(
widgetPos.x() - (width() / 10), widgetPos.y() + 25, width() / 5, height() / 2); widgetPos.x() - (width() / 10), widgetPos.y() + 25, width() / 5, height() / 2);
// notifDialog->move(widgetPos.x(), widgetPos.y());
// notifDialog->setFixedWidth(width() / 10);
// notifDialog->setFixedHeight(height() / 2);
notifDialog->raise(); notifDialog->raise();
notifDialog->show(); notifDialog->showPopup();
} }
void void
@ -1243,6 +1243,8 @@ ChatPage::sendTypingNotifications()
void void
ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err) ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
{ {
// TODO: Initial Sync should include mentions as well...
if (err) { if (err) {
const auto error = QString::fromStdString(err->matrix_error.error); const auto error = QString::fromStdString(err->matrix_error.error);
const auto msg = tr("Please try to login again: %1").arg(error); const auto msg = tr("Please try to login again: %1").arg(error);
@ -1280,6 +1282,7 @@ ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::Request
emit initializeViews(std::move(res.rooms)); emit initializeViews(std::move(res.rooms));
emit initializeRoomList(cache::client()->roomInfo()); emit initializeRoomList(cache::client()->roomInfo());
emit initializeMentions(cache::client()->getTimelineMentions());
cache::client()->calculateRoomReadStatus(); cache::client()->calculateRoomReadStatus();
emit syncTags(cache::client()->roomInfo().toStdMap()); emit syncTags(cache::client()->roomInfo().toStdMap());
@ -1334,37 +1337,7 @@ ChatPage::getProfileInfo()
emit setUserDisplayName(QString::fromStdString(res.display_name)); emit setUserDisplayName(QString::fromStdString(res.display_name));
if (cache::client()) { emit setUserAvatar(QString::fromStdString(res.avatar_url));
auto data = cache::client()->image(res.avatar_url);
if (!data.isNull()) {
emit setUserAvatar(QImage::fromData(data));
return;
}
}
if (res.avatar_url.empty())
return;
http::client()->download(
res.avatar_url,
[this, res](const std::string &data,
const std::string &,
const std::string &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn(
"failed to download user avatar: {} - {}",
mtx::errors::to_string(err->matrix_error.errcode),
err->matrix_error.error);
return;
}
if (cache::client())
cache::client()->saveImage(res.avatar_url, data);
emit setUserAvatar(
QImage::fromData(QByteArray(data.data(), data.size())));
});
}); });
http::client()->joined_groups( http::client()->joined_groups(

View file

@ -19,6 +19,7 @@
#include <atomic> #include <atomic>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <mtx/responses.hpp>
#include <QFrame> #include <QFrame>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -33,6 +34,7 @@
#include "MatrixClient.h" #include "MatrixClient.h"
#include "Utils.h" #include "Utils.h"
#include "notifications/Manager.h" #include "notifications/Manager.h"
#include "popups/UserMentions.h"
class OverlayModal; class OverlayModal;
class QuickSwitcher; class QuickSwitcher;
@ -44,7 +46,6 @@ class TimelineViewManager;
class TopRoomBar; class TopRoomBar;
class TypingDisplay; class TypingDisplay;
class UserInfoWidget; class UserInfoWidget;
class UserMentionsWidget;
class UserSettings; class UserSettings;
class NotificationsManager; class NotificationsManager;
@ -128,7 +129,7 @@ signals:
void ownProfileOk(); void ownProfileOk();
void setUserDisplayName(const QString &name); void setUserDisplayName(const QString &name);
void setUserAvatar(const QImage &avatar); void setUserAvatar(const QString &avatar);
void loggedOut(); void loggedOut();
void trySyncCb(); void trySyncCb();
@ -139,6 +140,7 @@ signals:
void initializeRoomList(QMap<QString, RoomInfo>); void initializeRoomList(QMap<QString, RoomInfo>);
void initializeViews(const mtx::responses::Rooms &rooms); void initializeViews(const mtx::responses::Rooms &rooms);
void initializeEmptyViews(const std::map<QString, mtx::responses::Timeline> &msgs); void initializeEmptyViews(const std::map<QString, mtx::responses::Timeline> &msgs);
void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs);
void syncUI(const mtx::responses::Rooms &rooms); void syncUI(const mtx::responses::Rooms &rooms);
void syncRoomlist(const std::map<QString, RoomInfo> &updates); void syncRoomlist(const std::map<QString, RoomInfo> &updates);
void syncTags(const std::map<QString, RoomInfo> &updates); void syncTags(const std::map<QString, RoomInfo> &updates);
@ -157,7 +159,7 @@ signals:
private slots: private slots:
void showUnreadMessageNotification(int count); void showUnreadMessageNotification(int count);
void updateTopBarAvatar(const QString &roomid, const QPixmap &img); void updateTopBarAvatar(const QString &roomid, const QString &img);
void changeTopRoomInfo(const QString &room_id); void changeTopRoomInfo(const QString &room_id);
void logout(); void logout();
void removeRoom(const QString &room_id); void removeRoom(const QString &room_id);
@ -208,7 +210,7 @@ private:
//! Send desktop notification for the received messages. //! Send desktop notification for the received messages.
void sendDesktopNotifications(const mtx::responses::Notifications &); void sendDesktopNotifications(const mtx::responses::Notifications &);
void showNotificationsDialog(const mtx::responses::Notifications &, const QPoint &point); void showNotificationsDialog(const QPoint &point);
QStringList generateTypingUsers(const QString &room_id, QStringList generateTypingUsers(const QString &room_id,
const std::vector<std::string> &typing_users); const std::vector<std::string> &typing_users);
@ -242,7 +244,7 @@ private:
UserInfoWidget *user_info_widget_; UserInfoWidget *user_info_widget_;
UserMentionsWidget *user_mentions_widget_; popups::UserMentions *user_mentions_popup_;
// Keeps track of the users currently typing on each room. // Keeps track of the users currently typing on each room.
std::map<QString, QList<QString>> typingUsers_; std::map<QString, QList<QString>> typingUsers_;

View file

@ -16,6 +16,8 @@ constexpr auto MAX_LOG_FILES = 3;
} }
namespace nhlog { namespace nhlog {
bool enable_debug_log_from_commandline = false;
void void
init(const std::string &file_path) init(const std::string &file_path)
{ {

View file

@ -18,4 +18,6 @@ db();
std::shared_ptr<spdlog::logger> std::shared_ptr<spdlog::logger>
crypto(); crypto();
extern bool enable_debug_log_from_commandline;
} }

View file

@ -19,8 +19,10 @@
#include <QDebug> #include <QDebug>
#include <QMouseEvent> #include <QMouseEvent>
#include <QPainter> #include <QPainter>
#include <QSettings>
#include <QtGlobal> #include <QtGlobal>
#include "AvatarProvider.h"
#include "Cache.h" #include "Cache.h"
#include "Config.h" #include "Config.h"
#include "RoomInfoListItem.h" #include "RoomInfoListItem.h"
@ -140,6 +142,8 @@ RoomInfoListItem::resizeEvent(QResizeEvent *)
void void
RoomInfoListItem::paintEvent(QPaintEvent *event) RoomInfoListItem::paintEvent(QPaintEvent *event)
{ {
bool rounded = QSettings().value("user/avatar/circles", true).toBool();
Q_UNUSED(event); Q_UNUSED(event);
QPainter p(this); QPainter p(this);
@ -287,7 +291,8 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(brush); p.setBrush(brush);
p.drawEllipse(avatarRegion.center(), wm.iconSize / 2, wm.iconSize / 2); rounded ? p.drawEllipse(avatarRegion.center(), wm.iconSize / 2, wm.iconSize / 2)
: p.drawRoundedRect(avatarRegion, 3, 3);
QFont bubbleFont; QFont bubbleFont;
bubbleFont.setPointSizeF(bubbleFont.pointSizeF() * 1.4); bubbleFont.setPointSizeF(bubbleFont.pointSizeF() * 1.4);
@ -300,7 +305,9 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
p.save(); p.save();
QPainterPath path; QPainterPath path;
path.addEllipse(wm.padding, wm.padding, wm.iconSize, wm.iconSize); rounded ? path.addEllipse(wm.padding, wm.padding, wm.iconSize, wm.iconSize)
: path.addRoundedRect(avatarRegion, 3, 3);
p.setClipPath(path); p.setClipPath(path);
p.drawPixmap(avatarRegion, roomAvatar_); p.drawPixmap(avatarRegion, roomAvatar_);
@ -434,10 +441,12 @@ RoomInfoListItem::mousePressEvent(QMouseEvent *event)
} }
void void
RoomInfoListItem::setAvatar(const QImage &img) RoomInfoListItem::setAvatar(const QString &avatar_url)
{ {
roomAvatar_ = utils::scaleImageToPixmap(img, IconSize); AvatarProvider::resolve(avatar_url, IconSize, this, [this](const QPixmap &img) {
roomAvatar_ = img;
update(); update();
});
} }
void void

View file

@ -73,7 +73,7 @@ public:
bool isPressed() const { return isPressed_; } bool isPressed() const { return isPressed_; }
int unreadMessageCount() const { return unreadMsgCount_; } int unreadMessageCount() const { return unreadMsgCount_; }
void setAvatar(const QImage &avatar_image); void setAvatar(const QString &avatar_url);
void setDescriptionMessage(const DescInfo &info); void setDescriptionMessage(const DescInfo &info);
DescInfo lastMessageInfo() const { return lastMsgInfo_; } DescInfo lastMessageInfo() const { return lastMsgInfo_; }

View file

@ -89,40 +89,7 @@ RoomList::updateAvatar(const QString &room_id, const QString &url)
if (url.isEmpty()) if (url.isEmpty())
return; return;
QByteArray savedImgData; emit updateRoomAvatarCb(room_id, url);
if (cache::client())
savedImgData = cache::client()->image(url);
if (savedImgData.isEmpty()) {
mtx::http::ThumbOpts opts;
opts.mxc_url = url.toStdString();
http::client()->get_thumbnail(
opts, [room_id, opts, this](const std::string &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn(
"failed to download room avatar: {} {} {}",
opts.mxc_url,
mtx::errors::to_string(err->matrix_error.errcode),
err->matrix_error.error);
return;
}
if (cache::client())
cache::client()->saveImage(opts.mxc_url, res);
auto data = QByteArray(res.data(), res.size());
QPixmap pixmap;
pixmap.loadFromData(data);
emit updateRoomAvatarCb(room_id, pixmap);
});
} else {
QPixmap img;
img.loadFromData(savedImgData);
updateRoomAvatar(room_id, img);
}
} }
void void
@ -252,7 +219,7 @@ RoomList::highlightSelectedRoom(const QString &room_id)
} }
void void
RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img) RoomList::updateRoomAvatar(const QString &roomid, const QString &img)
{ {
if (!roomExists(roomid)) { if (!roomExists(roomid)) {
nhlog::ui()->warn("avatar update on non-existent room_id: {}", nhlog::ui()->warn("avatar update on non-existent room_id: {}",
@ -260,7 +227,7 @@ RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
return; return;
} }
rooms_[roomid]->setAvatar(img.toImage()); rooms_[roomid]->setAvatar(img);
// Used to inform other widgets for the new image data. // Used to inform other widgets for the new image data.
emit roomAvatarChanged(roomid, img); emit roomAvatarChanged(roomid, img);

View file

@ -61,12 +61,12 @@ signals:
void totalUnreadMessageCountUpdated(int count); void totalUnreadMessageCountUpdated(int count);
void acceptInvite(const QString &room_id); void acceptInvite(const QString &room_id);
void declineInvite(const QString &room_id); void declineInvite(const QString &room_id);
void roomAvatarChanged(const QString &room_id, const QPixmap &img); void roomAvatarChanged(const QString &room_id, const QString &img);
void joinRoom(const QString &room_id); void joinRoom(const QString &room_id);
void updateRoomAvatarCb(const QString &room_id, const QPixmap &img); void updateRoomAvatarCb(const QString &room_id, const QString &img);
public slots: public slots:
void updateRoomAvatar(const QString &roomid, const QPixmap &img); void updateRoomAvatar(const QString &roomid, const QString &img);
void highlightSelectedRoom(const QString &room_id); void highlightSelectedRoom(const QString &room_id);
void updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount); void updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount);
void updateRoomDescription(const QString &roomid, const DescInfo &info); void updateRoomDescription(const QString &roomid, const DescInfo &info);

View file

@ -46,9 +46,8 @@ TopRoomBar::TopRoomBar(QWidget *parent)
topLayout_->setContentsMargins( topLayout_->setContentsMargins(
2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin); 2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, fontHeight * 2);
avatar_->setLetter(""); avatar_->setLetter("");
avatar_->setSize(fontHeight * 2);
textLayout_ = new QVBoxLayout(); textLayout_ = new QVBoxLayout();
textLayout_->setSpacing(0); textLayout_->setSpacing(0);
@ -183,7 +182,7 @@ TopRoomBar::reset()
} }
void void
TopRoomBar::updateRoomAvatar(const QImage &avatar_image) TopRoomBar::updateRoomAvatar(const QString &avatar_image)
{ {
avatar_->setImage(avatar_image); avatar_->setImage(avatar_image);
update(); update();

View file

@ -44,7 +44,7 @@ class TopRoomBar : public QWidget
public: public:
TopRoomBar(QWidget *parent = 0); TopRoomBar(QWidget *parent = 0);
void updateRoomAvatar(const QImage &avatar_image); void updateRoomAvatar(const QString &avatar_image);
void updateRoomAvatar(const QIcon &icon); void updateRoomAvatar(const QIcon &icon);
void updateRoomName(const QString &name); void updateRoomName(const QString &name);
void updateRoomTopic(QString topic); void updateRoomTopic(QString topic);

View file

@ -33,6 +33,14 @@ TypingDisplay::setUsers(const QStringList &uid)
text_.clear(); text_.clear();
QString temp = text_ +=
tr("%1 and %2 are typing",
"Multiple users are typing. First argument is a comma separated list of potentially "
"multiple users. Second argument is the last user of that list. (If only one user is "
"typing, %1 is empty. You should still use it in your string though to silence Qt "
"warnings.)",
uid.size());
if (uid.isEmpty()) { if (uid.isEmpty()) {
hide(); hide();
update(); update();
@ -40,12 +48,9 @@ TypingDisplay::setUsers(const QStringList &uid)
return; return;
} }
text_ = uid.join(", "); QStringList uidWithoutLast = uid;
uidWithoutLast.pop_back();
if (uid.size() == 1) text_ = temp.arg(uidWithoutLast.join(", ")).arg(uid.back());
text_ += tr(" is typing");
else if (uid.size() > 1)
text_ += tr(" are typing");
show(); show();
update(); update();

View file

@ -1,3 +1,4 @@
/* /*
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
* *
@ -52,10 +53,9 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
textLayout_->setSpacing(widgetMargin / 2); textLayout_->setSpacing(widgetMargin / 2);
textLayout_->setContentsMargins(widgetMargin * 2, widgetMargin, widgetMargin, widgetMargin); textLayout_->setContentsMargins(widgetMargin * 2, widgetMargin, widgetMargin, widgetMargin);
userAvatar_ = new Avatar(this); userAvatar_ = new Avatar(this, fontHeight * 2.5);
userAvatar_->setObjectName("userAvatar"); userAvatar_->setObjectName("userAvatar");
userAvatar_->setLetter(QChar('?')); userAvatar_->setLetter(QChar('?'));
userAvatar_->setSize(fontHeight * 2.5);
QFont nameFont; QFont nameFont;
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1); nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);
@ -134,14 +134,6 @@ UserInfoWidget::reset()
userAvatar_->setLetter(QChar('?')); userAvatar_->setLetter(QChar('?'));
} }
void
UserInfoWidget::setAvatar(const QImage &img)
{
avatar_image_ = img;
userAvatar_->setImage(img);
update();
}
void void
UserInfoWidget::setDisplayName(const QString &name) UserInfoWidget::setDisplayName(const QString &name)
{ {
@ -160,6 +152,14 @@ UserInfoWidget::setUserId(const QString &userid)
{ {
user_id_ = userid; user_id_ = userid;
userIdLabel_->setText(userid); userIdLabel_->setText(userid);
update();
}
void
UserInfoWidget::setAvatar(const QString &url)
{
userAvatar_->setImage(url);
update();
} }
void void

View file

@ -33,9 +33,9 @@ class UserInfoWidget : public QWidget
public: public:
UserInfoWidget(QWidget *parent = 0); UserInfoWidget(QWidget *parent = 0);
void setAvatar(const QImage &img);
void setDisplayName(const QString &name); void setDisplayName(const QString &name);
void setUserId(const QString &userid); void setUserId(const QString &userid);
void setAvatar(const QString &url);
void reset(); void reset();

View file

@ -1,309 +0,0 @@
#include <QDateTime>
#include <QDebug>
#include <QMouseEvent>
#include <QPainter>
#include <QtGlobal>
#include "MainWindow.h"
#include "UserMentionsWidget.h"
#include "Utils.h"
#include "ui/Ripple.h"
#include "ui/RippleOverlay.h"
constexpr int MaxUnreadCountDisplayed = 99;
struct WMetrics
{
int maxHeight;
int iconSize;
int padding;
int unit;
int unreadLineWidth;
int unreadLineOffset;
int inviteBtnX;
int inviteBtnY;
};
WMetrics
getWMetrics(const QFont &font)
{
WMetrics m;
const int height = QFontMetrics(font).lineSpacing();
m.unit = height;
m.maxHeight = std::ceil((double)height * 3.8);
m.iconSize = std::ceil((double)height * 2.8);
m.padding = std::ceil((double)height / 2.0);
m.unreadLineWidth = m.padding - m.padding / 3;
m.unreadLineOffset = m.padding - m.padding / 4;
m.inviteBtnX = m.iconSize + 2 * m.padding;
m.inviteBtnX = m.iconSize / 2.0 + m.padding + m.padding / 3.0;
return m;
}
UserMentionsWidget::UserMentionsWidget(QWidget *parent)
: QWidget(parent)
, isPressed_(false)
, unreadMsgCount_(0)
{
init(parent);
QFont f;
f.setPointSizeF(f.pointSizeF());
const int fontHeight = QFontMetrics(f).height();
const int widgetMargin = fontHeight / 3;
const int contentHeight = fontHeight * 3;
setFixedHeight(contentHeight + widgetMargin);
topLayout_ = new QHBoxLayout(this);
topLayout_->setSpacing(0);
topLayout_->setMargin(widgetMargin);
}
void
UserMentionsWidget::init(QWidget *parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setMouseTracking(true);
setAttribute(Qt::WA_Hover);
setFixedHeight(getWMetrics(QFont{}).maxHeight);
QPainterPath path;
path.addRect(0, 0, parent->width(), height());
ripple_overlay_ = new RippleOverlay(this);
ripple_overlay_->setClipPath(path);
ripple_overlay_->setClipping(true);
unreadCountFont_.setPointSizeF(unreadCountFont_.pointSizeF() * 0.8);
unreadCountFont_.setBold(true);
bubbleDiameter_ = QFontMetrics(unreadCountFont_).averageCharWidth() * 3;
}
// void
// UserMentionsWidget::resizeEvent(QResizeEvent *event)
// {
// Q_UNUSED(event);
// const auto sz = utils::calculateSidebarSizes(QFont{});
// if (width() <= sz.small) {
// topLayout_->setContentsMargins(0, 0, logoutButtonSize_, 0);
// } else {
// topLayout_->setMargin(5);
// }
// QWidget::resizeEvent(event);
// }
void
UserMentionsWidget::setPressedState(bool state)
{
if (isPressed_ != state) {
isPressed_ = state;
update();
}
}
void
UserMentionsWidget::resizeEvent(QResizeEvent *)
{
// Update ripple's clipping path.
QPainterPath path;
path.addRect(0, 0, width(), height());
const auto sidebarSizes = utils::calculateSidebarSizes(QFont{});
if (width() > sidebarSizes.small)
setToolTip("");
else
setToolTip("");
ripple_overlay_->setClipPath(path);
ripple_overlay_->setClipping(true);
}
void
UserMentionsWidget::mousePressEvent(QMouseEvent *event)
{
if (event->buttons() == Qt::RightButton) {
QWidget::mousePressEvent(event);
return;
}
emit clicked();
setPressedState(true);
// Ripple on mouse position by default.
QPoint pos = event->pos();
qreal radiusEndValue = static_cast<qreal>(width()) / 3;
Ripple *ripple = new Ripple(pos);
ripple->setRadiusEndValue(radiusEndValue);
ripple->setOpacityStartValue(0.15);
ripple->setColor(QColor("white"));
ripple->radiusAnimation()->setDuration(200);
ripple->opacityAnimation()->setDuration(400);
ripple_overlay_->addRipple(ripple);
}
void
UserMentionsWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter p(this);
p.setRenderHint(QPainter::TextAntialiasing);
p.setRenderHint(QPainter::SmoothPixmapTransform);
p.setRenderHint(QPainter::Antialiasing);
auto wm = getWMetrics(QFont{});
QPen titlePen(titleColor_);
QPen subtitlePen(subtitleColor_);
QFontMetrics metrics(QFont{});
if (isPressed_) {
p.fillRect(rect(), highlightedBackgroundColor_);
titlePen.setColor(highlightedTitleColor_);
subtitlePen.setColor(highlightedSubtitleColor_);
} else if (underMouse()) {
p.fillRect(rect(), hoverBackgroundColor_);
titlePen.setColor(hoverTitleColor_);
subtitlePen.setColor(hoverSubtitleColor_);
} else {
p.fillRect(rect(), backgroundColor_);
titlePen.setColor(titleColor_);
subtitlePen.setColor(subtitleColor_);
}
// Description line with the default font.
int bottom_y = wm.maxHeight - wm.padding - metrics.ascent() / 2;
const auto sidebarSizes = utils::calculateSidebarSizes(QFont{});
if (width() > sidebarSizes.small) {
QFont headingFont;
headingFont.setWeight(QFont::Medium);
p.setFont(headingFont);
p.setPen(titlePen);
QFont tsFont;
tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9);
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
const int msgStampWidth = QFontMetrics(tsFont).width("timestamp") + 4;
#else
const int msgStampWidth = QFontMetrics(tsFont).horizontalAdvance("timestamp") + 4;
#endif
// We use the full width of the widget if there is no unread msg bubble.
// const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0;
// Name line.
QFontMetrics fontNameMetrics(headingFont);
int top_y = 2 * wm.padding + fontNameMetrics.ascent() / 2;
const auto name = metrics.elidedText(
"Mentions",
Qt::ElideRight,
(width() - wm.iconSize - 2 * wm.padding - msgStampWidth) * 0.8);
p.drawText(QPoint(2 * wm.padding + wm.iconSize, top_y), name);
p.setFont(QFont{});
p.setPen(subtitlePen);
// The limit is the space between the end of the avatar and the start of the
// timestamp.
int usernameLimit =
std::max(0, width() - 3 * wm.padding - msgStampWidth - wm.iconSize - 20);
auto userName =
metrics.elidedText("Show Mentioned Messages", Qt::ElideRight, usernameLimit);
p.setFont(QFont{});
p.drawText(QPoint(2 * wm.padding + wm.iconSize, bottom_y), userName);
// We show the last message timestamp.
p.save();
if (isPressed_) {
p.setPen(QPen(highlightedTimestampColor_));
} else if (underMouse()) {
p.setPen(QPen(hoverTimestampColor_));
} else {
p.setPen(QPen(timestampColor_));
}
// p.setFont(tsFont);
// p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y), "timestamp");
p.restore();
}
p.setPen(Qt::NoPen);
if (unreadMsgCount_ > 0) {
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(mentionedColor());
if (isPressed_)
brush.setColor(bubbleFgColor());
p.setBrush(brush);
p.setPen(Qt::NoPen);
p.setFont(unreadCountFont_);
// Extra space on the x-axis to accomodate the extra character space
// inside the bubble.
const int x_width = unreadMsgCount_ > MaxUnreadCountDisplayed
? QFontMetrics(p.font()).averageCharWidth()
: 0;
QRectF r(width() - bubbleDiameter_ - wm.padding - x_width,
bottom_y - bubbleDiameter_ / 2 - 5,
bubbleDiameter_ + x_width,
bubbleDiameter_);
if (width() == sidebarSizes.small)
r = QRectF(width() - bubbleDiameter_ - 5,
height() - bubbleDiameter_ - 5,
bubbleDiameter_ + x_width,
bubbleDiameter_);
p.setPen(Qt::NoPen);
p.drawEllipse(r);
p.setPen(QPen(bubbleFgColor()));
if (isPressed_)
p.setPen(QPen(bubbleBgColor()));
auto countTxt = unreadMsgCount_ > MaxUnreadCountDisplayed
? QString("99+")
: QString::number(unreadMsgCount_);
p.setBrush(Qt::NoBrush);
p.drawText(r.translated(0, -0.5), Qt::AlignCenter, countTxt);
}
if (!isPressed_ && hasUnreadMessages_) {
QPen pen;
pen.setWidth(wm.unreadLineWidth);
pen.setColor(highlightedBackgroundColor_);
p.setPen(pen);
p.drawLine(0, wm.unreadLineOffset, 0, height() - wm.unreadLineOffset);
}
}

View file

@ -1,164 +0,0 @@
#pragma once
#include <QColor>
#include <QHBoxLayout>
#include <QLabel>
#include <QLayout>
#include <QWidget>
class FlatButton;
class RippleOverlay;
class UserMentionsWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE
setHighlightedBackgroundColor)
Q_PROPERTY(
QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor)
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
Q_PROPERTY(QColor avatarBgColor READ avatarBgColor WRITE setAvatarBgColor)
Q_PROPERTY(QColor avatarFgColor READ avatarFgColor WRITE setAvatarFgColor)
Q_PROPERTY(QColor bubbleBgColor READ bubbleBgColor WRITE setBubbleBgColor)
Q_PROPERTY(QColor bubbleFgColor READ bubbleFgColor WRITE setBubbleFgColor)
Q_PROPERTY(QColor titleColor READ titleColor WRITE setTitleColor)
Q_PROPERTY(QColor subtitleColor READ subtitleColor WRITE setSubtitleColor)
Q_PROPERTY(QColor timestampColor READ timestampColor WRITE setTimestampColor)
Q_PROPERTY(QColor highlightedTimestampColor READ highlightedTimestampColor WRITE
setHighlightedTimestampColor)
Q_PROPERTY(QColor hoverTimestampColor READ hoverTimestampColor WRITE setHoverTimestampColor)
Q_PROPERTY(
QColor highlightedTitleColor READ highlightedTitleColor WRITE setHighlightedTitleColor)
Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
setHighlightedSubtitleColor)
Q_PROPERTY(QColor hoverTitleColor READ hoverTitleColor WRITE setHoverTitleColor)
Q_PROPERTY(QColor hoverSubtitleColor READ hoverSubtitleColor WRITE setHoverSubtitleColor)
Q_PROPERTY(QColor mentionedColor READ mentionedColor WRITE setMentionedColor)
Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor)
Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
public:
UserMentionsWidget(QWidget *parent = 0);
void updateUnreadMessageCount(int count);
void clearUnreadMessageCount() { updateUnreadMessageCount(0); };
bool isPressed() const { return isPressed_; }
int unreadMessageCount() const { return unreadMsgCount_; }
QColor borderColor() const { return borderColor_; }
void setBorderColor(QColor &color) { borderColor_ = color; }
QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
QColor hoverTitleColor() const { return hoverTitleColor_; }
QColor hoverSubtitleColor() const { return hoverSubtitleColor_; }
QColor hoverTimestampColor() const { return hoverTimestampColor_; }
QColor backgroundColor() const { return backgroundColor_; }
QColor avatarBgColor() const { return avatarBgColor_; }
QColor avatarFgColor() const { return avatarFgColor_; }
QColor highlightedTitleColor() const { return highlightedTitleColor_; }
QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
QColor highlightedTimestampColor() const { return highlightedTimestampColor_; }
QColor titleColor() const { return titleColor_; }
QColor subtitleColor() const { return subtitleColor_; }
QColor timestampColor() const { return timestampColor_; }
QColor btnColor() const { return btnColor_; }
QColor btnTextColor() const { return btnTextColor_; }
QColor bubbleFgColor() const { return bubbleFgColor_; }
QColor bubbleBgColor() const { return bubbleBgColor_; }
QColor mentionedColor() const { return mentionedFontColor_; }
void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
void setHoverSubtitleColor(QColor &color) { hoverSubtitleColor_ = color; }
void setHoverTitleColor(QColor &color) { hoverTitleColor_ = color; }
void setHoverTimestampColor(QColor &color) { hoverTimestampColor_ = color; }
void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
void setTimestampColor(QColor &color) { timestampColor_ = color; }
void setAvatarFgColor(QColor &color) { avatarFgColor_ = color; }
void setAvatarBgColor(QColor &color) { avatarBgColor_ = color; }
void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; }
void setHighlightedTimestampColor(QColor &color) { highlightedTimestampColor_ = color; }
void setTitleColor(QColor &color) { titleColor_ = color; }
void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
void setBtnColor(QColor &color) { btnColor_ = color; }
void setBtnTextColor(QColor &color) { btnTextColor_ = color; }
void setBubbleFgColor(QColor &color) { bubbleFgColor_ = color; }
void setBubbleBgColor(QColor &color) { bubbleBgColor_ = color; }
void setMentionedColor(QColor &color) { mentionedFontColor_ = color; }
signals:
void clicked();
public slots:
void setPressedState(bool state);
protected:
void mousePressEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
void init(QWidget *parent);
RippleOverlay *ripple_overlay_;
bool isPressed_ = false;
bool hasUnreadMessages_ = true;
int unreadMsgCount_ = 0;
QHBoxLayout *topLayout_;
QColor borderColor_;
QColor highlightedBackgroundColor_;
QColor hoverBackgroundColor_;
QColor backgroundColor_;
QColor highlightedTitleColor_;
QColor highlightedSubtitleColor_;
QColor titleColor_;
QColor subtitleColor_;
QColor hoverTitleColor_;
QColor hoverSubtitleColor_;
QColor btnColor_;
QColor btnTextColor_;
QRectF acceptBtnRegion_;
QRectF declineBtnRegion_;
// Fonts
QColor mentionedFontColor_;
QFont unreadCountFont_;
int bubbleDiameter_;
QColor timestampColor_;
QColor highlightedTimestampColor_;
QColor hoverTimestampColor_;
QColor avatarBgColor_;
QColor avatarFgColor_;
QColor bubbleBgColor_;
QColor bubbleFgColor_;
};

View file

@ -22,9 +22,11 @@
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QMessageBox> #include <QMessageBox>
#include <QProcessEnvironment>
#include <QPushButton> #include <QPushButton>
#include <QScrollArea> #include <QScrollArea>
#include <QSettings> #include <QSettings>
#include <QString>
#include <QTextStream> #include <QTextStream>
#include "Config.h" #include "Config.h"
@ -49,8 +51,9 @@ UserSettings::load()
isGroupViewEnabled_ = settings.value("user/group_view", true).toBool(); isGroupViewEnabled_ = settings.value("user/group_view", true).toBool();
isTypingNotificationsEnabled_ = settings.value("user/typing_notifications", true).toBool(); isTypingNotificationsEnabled_ = settings.value("user/typing_notifications", true).toBool();
isReadReceiptsEnabled_ = settings.value("user/read_receipts", true).toBool(); isReadReceiptsEnabled_ = settings.value("user/read_receipts", true).toBool();
theme_ = settings.value("user/theme", "light").toString(); theme_ = settings.value("user/theme", defaultTheme_).toString();
font_ = settings.value("user/font_family", "default").toString(); font_ = settings.value("user/font_family", "default").toString();
avatarCircles_ = settings.value("user/avatar/circles", true).toBool();
emojiFont_ = settings.value("user/emoji_font_family", "default").toString(); emojiFont_ = settings.value("user/emoji_font_family", "default").toString();
baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble(); baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble();
@ -116,6 +119,10 @@ UserSettings::save()
settings.setValue("start_in_tray", isStartInTrayEnabled_); settings.setValue("start_in_tray", isStartInTrayEnabled_);
settings.endGroup(); settings.endGroup();
settings.beginGroup("avatar");
settings.setValue("circles", avatarCircles_);
settings.endGroup();
settings.setValue("font_size", baseFontSize_); settings.setValue("font_size", baseFontSize_);
settings.setValue("typing_notifications", isTypingNotificationsEnabled_); settings.setValue("typing_notifications", isTypingNotificationsEnabled_);
settings.setValue("read_receipts", isReadReceiptsEnabled_); settings.setValue("read_receipts", isReadReceiptsEnabled_);
@ -190,6 +197,15 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
groupViewLayout->addWidget(groupViewLabel); groupViewLayout->addWidget(groupViewLabel);
groupViewLayout->addWidget(groupViewToggle_, 0, Qt::AlignRight); groupViewLayout->addWidget(groupViewToggle_, 0, Qt::AlignRight);
auto avatarViewLayout = new QHBoxLayout;
avatarViewLayout->setContentsMargins(0, OptionMargin, 0, OptionMargin);
auto avatarViewLabel = new QLabel(tr("Circular Avatars"), this);
avatarViewLabel->setFont(font);
avatarCircles_ = new Toggle(this);
avatarViewLayout->addWidget(avatarViewLabel);
avatarViewLayout->addWidget(avatarCircles_, 0, Qt::AlignRight);
auto typingLayout = new QHBoxLayout; auto typingLayout = new QHBoxLayout;
typingLayout->setContentsMargins(0, OptionMargin, 0, OptionMargin); typingLayout->setContentsMargins(0, OptionMargin, 0, OptionMargin);
auto typingLabel = new QLabel(tr("Typing notifications"), this); auto typingLabel = new QLabel(tr("Typing notifications"), this);
@ -366,6 +382,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
mainLayout_->addLayout(startInTrayOptionLayout_); mainLayout_->addLayout(startInTrayOptionLayout_);
mainLayout_->addWidget(new HorizontalLine(this)); mainLayout_->addWidget(new HorizontalLine(this));
mainLayout_->addLayout(groupViewLayout); mainLayout_->addLayout(groupViewLayout);
mainLayout_->addLayout(avatarViewLayout);
mainLayout_->addWidget(new HorizontalLine(this)); mainLayout_->addWidget(new HorizontalLine(this));
mainLayout_->addLayout(typingLayout); mainLayout_->addLayout(typingLayout);
mainLayout_->addLayout(receiptsLayout); mainLayout_->addLayout(receiptsLayout);
@ -446,6 +463,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
settings_->setGroupView(!isDisabled); settings_->setGroupView(!isDisabled);
}); });
connect(avatarCircles_, &Toggle::toggled, this, [this](bool isDisabled) {
settings_->setAvatarCircles(!isDisabled);
});
connect(typingNotifications_, &Toggle::toggled, this, [this](bool isDisabled) { connect(typingNotifications_, &Toggle::toggled, this, [this](bool isDisabled) {
settings_->setTypingNotifications(!isDisabled); settings_->setTypingNotifications(!isDisabled);
}); });

View file

@ -22,6 +22,7 @@
#include <QFrame> #include <QFrame>
#include <QLabel> #include <QLabel>
#include <QLayout> #include <QLayout>
#include <QProcessEnvironment>
#include <QSharedPointer> #include <QSharedPointer>
#include <QWidget> #include <QWidget>
@ -85,7 +86,13 @@ public:
save(); save();
} }
QString theme() const { return !theme_.isEmpty() ? theme_ : "light"; } void setAvatarCircles(bool state)
{
avatarCircles_ = state;
save();
}
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
bool isTrayEnabled() const { return isTrayEnabled_; } bool isTrayEnabled() const { return isTrayEnabled_; }
bool isStartInTrayEnabled() const { return isStartInTrayEnabled_; } bool isStartInTrayEnabled() const { return isStartInTrayEnabled_; }
bool isGroupViewEnabled() const { return isGroupViewEnabled_; } bool isGroupViewEnabled() const { return isGroupViewEnabled_; }
@ -100,6 +107,11 @@ signals:
void groupViewStateChanged(bool state); void groupViewStateChanged(bool state);
private: private:
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
QString defaultTheme_ =
QProcessEnvironment::systemEnvironment().value("QT_QPA_PLATFORMTHEME", "").isEmpty()
? "light"
: "system";
QString theme_; QString theme_;
bool isTrayEnabled_; bool isTrayEnabled_;
bool isStartInTrayEnabled_; bool isStartInTrayEnabled_;
@ -107,6 +119,7 @@ private:
bool isTypingNotificationsEnabled_; bool isTypingNotificationsEnabled_;
bool isReadReceiptsEnabled_; bool isReadReceiptsEnabled_;
bool hasDesktopNotifications_; bool hasDesktopNotifications_;
bool avatarCircles_;
double baseFontSize_; double baseFontSize_;
QString font_; QString font_;
QString emojiFont_; QString emojiFont_;
@ -156,6 +169,7 @@ private:
Toggle *typingNotifications_; Toggle *typingNotifications_;
Toggle *readReceipts_; Toggle *readReceipts_;
Toggle *desktopNotifications_; Toggle *desktopNotifications_;
Toggle *avatarCircles_;
QLabel *deviceFingerprintValue_; QLabel *deviceFingerprintValue_;
QLabel *deviceIdValue_; QLabel *deviceIdValue_;

View file

@ -4,6 +4,7 @@
#include <QComboBox> #include <QComboBox>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QGuiApplication> #include <QGuiApplication>
#include <QProcessEnvironment>
#include <QScreen> #include <QScreen>
#include <QSettings> #include <QSettings>
#include <QTextDocument> #include <QTextDocument>
@ -99,13 +100,13 @@ utils::descriptiveTime(const QDateTime &then)
const auto days = then.daysTo(now); const auto days = then.daysTo(now);
if (days == 0) if (days == 0)
return then.toString("HH:mm"); return then.time().toString(Qt::DefaultLocaleShortDate);
else if (days < 2) else if (days < 2)
return QString("Yesterday"); return QString(QCoreApplication::translate("descriptiveTime", "Yesterday"));
else if (days < 365) else if (days < 7)
return then.toString("dd/MM"); return then.toString("dddd");
return then.toString("dd/MM/yy"); return then.date().toString(Qt::DefaultLocaleShortDate);
} }
DescInfo DescInfo
@ -147,7 +148,7 @@ utils::getMessageDescription(const TimelineEvent &event,
DescInfo info; DescInfo info;
if (sender == localUser) if (sender == localUser)
info.username = "You"; info.username = QCoreApplication::translate("utils", "You");
else else
info.username = username; info.username = username;
@ -323,10 +324,25 @@ utils::linkifyMessage(const QString &body)
return doc; return doc;
} }
QByteArray escapeRawHtml(const QByteArray &data) {
QByteArray buffer;
const size_t length = data.size();
buffer.reserve(length);
for(size_t pos = 0; pos != length; ++pos) {
switch(data.at(pos)) {
case '&': buffer.append("&amp;"); break;
case '<': buffer.append("&lt;"); break;
case '>': buffer.append("&gt;"); break;
default: buffer.append(data.at(pos)); break;
}
}
return buffer;
}
QString QString
utils::markdownToHtml(const QString &text) utils::markdownToHtml(const QString &text)
{ {
const auto str = text.toUtf8(); const auto str = escapeRawHtml(text.toUtf8());
const char *tmp_buf = const char *tmp_buf =
cmark_markdown_to_html(str.constData(), str.size(), CMARK_OPT_DEFAULT); cmark_markdown_to_html(str.constData(), str.size(), CMARK_OPT_DEFAULT);
@ -366,16 +382,16 @@ utils::getQuoteBody(const RelatedInfo &related)
return markdownToHtml(related.quoted_body); return markdownToHtml(related.quoted_body);
} }
case MsgType::File: { case MsgType::File: {
return QString("sent a file."); return QString(QCoreApplication::translate("utils", "sent a file."));
} }
case MsgType::Image: { case MsgType::Image: {
return QString("sent an image."); return QString(QCoreApplication::translate("utils", "sent an image."));
} }
case MsgType::Audio: { case MsgType::Audio: {
return QString("sent an audio file."); return QString(QCoreApplication::translate("utils", "sent an audio file."));
} }
case MsgType::Video: { case MsgType::Video: {
return QString("sent a video"); return QString(QCoreApplication::translate("utils", "sent a video"));
} }
default: { default: {
return related.quoted_body; return related.quoted_body;
@ -387,14 +403,20 @@ QString
utils::linkColor() utils::linkColor()
{ {
QSettings settings; QSettings settings;
const auto theme = settings.value("user/theme", "light").toString(); // 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();
if (theme == "light") if (theme == "light") {
return "#0077b5"; return "#0077b5";
else if (theme == "dark") } else if (theme == "dark") {
return "#38A3D8"; return "#38A3D8";
} else {
return QPalette().color(QPalette::Link).name(); return QPalette().color(QPalette::Link).name();
}
} }
uint32_t uint32_t

View file

@ -9,6 +9,7 @@
#include "timeline/widgets/ImageItem.h" #include "timeline/widgets/ImageItem.h"
#include "timeline/widgets/VideoItem.h" #include "timeline/widgets/VideoItem.h"
#include <QCoreApplication>
#include <QDateTime> #include <QDateTime>
#include <QPixmap> #include <QPixmap>
#include <mtx/events/collections.hpp> #include <mtx/events/collections.hpp>
@ -79,7 +80,9 @@ event_body(const mtx::events::collections::TimelineEvents &event);
//! Match widgets/events with a description message. //! Match widgets/events with a description message.
template<class T> template<class T>
QString QString
messageDescription(const QString &username = "", const QString &body = "") messageDescription(const QString &username = "",
const QString &body = "",
const bool isLocal = false)
{ {
using Audio = mtx::events::RoomEvent<mtx::events::msg::Audio>; using Audio = mtx::events::RoomEvent<mtx::events::msg::Audio>;
using Emote = mtx::events::RoomEvent<mtx::events::msg::Emote>; using Emote = mtx::events::RoomEvent<mtx::events::msg::Emote>;
@ -91,24 +94,41 @@ messageDescription(const QString &username = "", const QString &body = "")
using Video = mtx::events::RoomEvent<mtx::events::msg::Video>; using Video = mtx::events::RoomEvent<mtx::events::msg::Video>;
using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>; using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>;
if (std::is_same<T, AudioItem>::value || std::is_same<T, Audio>::value) // Sometimes the verb form of sent changes in some languages depending on the actor.
return QString("sent an audio clip"); auto remoteSent = QCoreApplication::translate(
else if (std::is_same<T, ImageItem>::value || std::is_same<T, Image>::value) "message-description: ", "sent", "For when you are the sender");
return QString("sent an image"); auto localSent = QCoreApplication::translate(
else if (std::is_same<T, FileItem>::value || std::is_same<T, File>::value) "message-description:", "sent", "For when someone else is the sender");
return QString("sent a file"); QString sentVerb = isLocal ? localSent : remoteSent;
else if (std::is_same<T, VideoItem>::value || std::is_same<T, Video>::value) if (std::is_same<T, AudioItem>::value || std::is_same<T, Audio>::value) {
return QString("sent a video clip"); return QCoreApplication::translate("message-description sent:", "%1 an audio clip")
else if (std::is_same<T, StickerItem>::value || std::is_same<T, Sticker>::value) .arg(sentVerb);
return QString("sent a sticker"); } else if (std::is_same<T, ImageItem>::value || std::is_same<T, Image>::value) {
else if (std::is_same<T, Notice>::value) return QCoreApplication::translate("message-description sent:", "%1 an image")
return QString("sent a notification"); .arg(sentVerb);
else if (std::is_same<T, Text>::value) } else if (std::is_same<T, FileItem>::value || std::is_same<T, File>::value) {
return QCoreApplication::translate("message-description sent:", "%1 a file")
.arg(sentVerb);
} else if (std::is_same<T, VideoItem>::value || std::is_same<T, Video>::value) {
return QCoreApplication::translate("message-description sent:", "%1 a video clip")
.arg(sentVerb);
} else if (std::is_same<T, StickerItem>::value || std::is_same<T, Sticker>::value) {
return QCoreApplication::translate("message-description sent:", "%1 a sticker")
.arg(sentVerb);
} else if (std::is_same<T, Notice>::value) {
return QCoreApplication::translate("message-description sent:", "%1 a notification")
.arg(sentVerb);
} else if (std::is_same<T, Text>::value) {
return QString(": %1").arg(body); return QString(": %1").arg(body);
else if (std::is_same<T, Emote>::value) } else if (std::is_same<T, Emote>::value) {
return QString("* %1 %2").arg(username).arg(body); return QString("* %1 %2").arg(username).arg(body);
else if (std::is_same<T, Encrypted>::value) } else if (std::is_same<T, Encrypted>::value) {
return QString("sent an encrypted message"); return QCoreApplication::translate("message-description sent:",
"%1 an encrypted message")
.arg(sentVerb);
} else {
return QCoreApplication::translate("utils", "Unknown Message Type");
}
} }
template<class T, class Event> template<class T, class Event>
@ -129,10 +149,12 @@ createDescriptionInfo(const Event &event, const QString &localUser, const QStrin
return DescInfo{ return DescInfo{
QString::fromStdString(msg.event_id), QString::fromStdString(msg.event_id),
isEmote ? "" : (sender == localUser ? "You" : username), isEmote ? ""
: (sender == localUser ? QCoreApplication::translate("utils", "You") : username),
sender, sender,
(isText || isEmote) (isText || isEmote)
? messageDescription<T>(username, QString::fromStdString(msg.content.body).trimmed()) ? messageDescription<T>(
username, QString::fromStdString(msg.content.body).trimmed(), sender == localUser)
: QString(" %1").arg(messageDescription<T>()), : QString(" %1").arg(messageDescription<T>()),
utils::descriptiveTime(ts), utils::descriptiveTime(ts),
ts}; ts};

View file

@ -9,7 +9,6 @@
#include "dialogs/MemberList.h" #include "dialogs/MemberList.h"
#include "AvatarProvider.h"
#include "Cache.h" #include "Cache.h"
#include "ChatPage.h" #include "ChatPage.h"
#include "Config.h" #include "Config.h"
@ -28,17 +27,10 @@ MemberItem::MemberItem(const RoomMember &member, QWidget *parent)
textLayout_->setMargin(0); textLayout_->setMargin(0);
textLayout_->setSpacing(0); textLayout_->setSpacing(0);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 44);
avatar_->setSize(44);
avatar_->setLetter(utils::firstChar(member.display_name)); avatar_->setLetter(utils::firstChar(member.display_name));
if (!member.avatar.isNull()) avatar_->setImage(ChatPage::instance()->currentRoom(), member.user_id);
avatar_->setImage(member.avatar);
else
AvatarProvider::resolve(ChatPage::instance()->currentRoom(),
member.user_id,
this,
[this](const QImage &img) { avatar_->setImage(img); });
QFont nameFont; QFont nameFont;
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1); nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);
@ -97,7 +89,7 @@ MemberList::MemberList(const QString &room_id, QWidget *parent)
topLabel_->setAlignment(Qt::AlignCenter); topLabel_->setAlignment(Qt::AlignCenter);
topLabel_->setFont(font); topLabel_->setFont(font);
auto okBtn = new QPushButton("OK", this); auto okBtn = new QPushButton(tr("OK"), this);
auto buttonLayout = new QHBoxLayout(); auto buttonLayout = new QHBoxLayout();
buttonLayout->setSpacing(15); buttonLayout->setSpacing(15);
@ -126,7 +118,7 @@ MemberList::MemberList(const QString &room_id, QWidget *parent)
qCritical() << e.what(); qCritical() << e.what();
} }
auto closeShortcut = new QShortcut(QKeySequence(tr("ESC")), this); auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
connect(closeShortcut, &QShortcut::activated, this, &MemberList::close); connect(closeShortcut, &QShortcut::activated, this, &MemberList::close);
connect(okBtn, &QPushButton::clicked, this, &MemberList::close); connect(okBtn, &QPushButton::clicked, this, &MemberList::close);
} }

View file

@ -37,8 +37,7 @@ ReceiptItem::ReceiptItem(QWidget *parent,
auto displayName = Cache::displayName(room_id, user_id); auto displayName = Cache::displayName(room_id, user_id);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 44);
avatar_->setSize(44);
avatar_->setLetter(utils::firstChar(displayName)); avatar_->setLetter(utils::firstChar(displayName));
// If it's a matrix id we use the second letter. // If it's a matrix id we use the second letter.
@ -56,10 +55,7 @@ ReceiptItem::ReceiptItem(QWidget *parent,
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addLayout(textLayout_, 1); topLayout_->addLayout(textLayout_, 1);
AvatarProvider::resolve(ChatPage::instance()->currentRoom(), avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
user_id,
this,
[this](const QImage &img) { avatar_->setImage(img); });
} }
void void
@ -78,13 +74,15 @@ ReceiptItem::dateFormat(const QDateTime &then) const
auto days = then.daysTo(now); auto days = then.daysTo(now);
if (days == 0) if (days == 0)
return QString("Today %1").arg(then.toString("HH:mm")); return tr("Today %1").arg(then.time().toString(Qt::DefaultLocaleShortDate));
else if (days < 2) else if (days < 2)
return QString("Yesterday %1").arg(then.toString("HH:mm")); return tr("Yesterday %1").arg(then.time().toString(Qt::DefaultLocaleShortDate));
else if (days < 365) else if (days < 7)
return then.toString("dd/MM HH:mm"); return QString("%1 %2")
.arg(then.toString("dddd"))
.arg(then.time().toString(Qt::DefaultLocaleShortDate));
return then.toString("dd/MM/yy"); return then.toString(Qt::DefaultLocaleShortDate);
} }
ReadReceipts::ReadReceipts(QWidget *parent) ReadReceipts::ReadReceipts(QWidget *parent)
@ -131,7 +129,7 @@ ReadReceipts::ReadReceipts(QWidget *parent)
layout->addWidget(userList_); layout->addWidget(userList_);
layout->addLayout(buttonLayout); layout->addLayout(buttonLayout);
auto closeShortcut = new QShortcut(QKeySequence(tr("ESC")), this); auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
connect(closeShortcut, &QShortcut::activated, this, &ReadReceipts::close); connect(closeShortcut, &QShortcut::activated, this, &ReadReceipts::close);
connect(okBtn, &QPushButton::clicked, this, &ReadReceipts::close); connect(okBtn, &QPushButton::clicked, this, &ReadReceipts::close);
} }

View file

@ -350,12 +350,12 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
keyRequestsToggle_->hide(); keyRequestsToggle_->hide();
} }
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 128);
avatar_->setSize(128);
if (avatarImg_.isNull()) if (avatarImg_.isNull())
avatar_->setLetter(utils::firstChar(QString::fromStdString(info_.name))); avatar_->setLetter(utils::firstChar(QString::fromStdString(info_.name)));
else else
avatar_->setImage(avatarImg_); avatar_->setImage(room_id_,
QString::fromStdString(http::client()->user_id().to_string()));
if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) { if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) {
auto filter = new ClickableFilter(this); auto filter = new ClickableFilter(this);
@ -438,7 +438,7 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
resetErrorLabel(); resetErrorLabel();
}); });
auto closeShortcut = new QShortcut(QKeySequence(tr("ESC")), this); auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
connect(closeShortcut, &QShortcut::activated, this, &RoomSettings::close); connect(closeShortcut, &QShortcut::activated, this, &RoomSettings::close);
connect(okBtn, &QPushButton::clicked, this, &RoomSettings::close); connect(okBtn, &QPushButton::clicked, this, &RoomSettings::close);
} }
@ -487,7 +487,7 @@ RoomSettings::retrieveRoomInfo()
try { try {
usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString()); usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString());
info_ = cache::client()->singleRoomInfo(room_id_.toStdString()); info_ = cache::client()->singleRoomInfo(room_id_.toStdString());
setAvatar(QImage::fromData(cache::client()->image(info_.avatar_url))); setAvatar();
} catch (const lmdb::error &e) { } catch (const lmdb::error &e) {
nhlog::db()->warn("failed to retrieve room info from cache: {}", nhlog::db()->warn("failed to retrieve room info from cache: {}",
room_id_.toStdString()); room_id_.toStdString());
@ -633,14 +633,13 @@ RoomSettings::displayErrorMessage(const QString &msg)
} }
void void
RoomSettings::setAvatar(const QImage &img) RoomSettings::setAvatar()
{ {
stopLoadingSpinner(); stopLoadingSpinner();
avatarImg_ = img;
if (avatar_) if (avatar_)
avatar_->setImage(img); avatar_->setImage(room_id_,
QString::fromStdString(http::client()->user_id().to_string()));
} }
void void
@ -668,12 +667,12 @@ RoomSettings::updateAvatar()
QFile file{fileName, this}; QFile file{fileName, this};
if (format != "image") { if (format != "image") {
displayErrorMessage(tr("The selected media is not an image")); displayErrorMessage(tr("The selected file is not an image"));
return; return;
} }
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
displayErrorMessage(tr("Error while reading media: %1").arg(file.errorString())); displayErrorMessage(tr("Error while reading file: %1").arg(file.errorString()));
return; return;
} }
@ -733,7 +732,7 @@ RoomSettings::updateAvatar()
return; return;
} }
emit proxy->avatarChanged(QImage::fromData(content)); emit proxy->avatarChanged();
}); });
}); });
} }

View file

@ -52,7 +52,7 @@ class ThreadProxy : public QObject
signals: signals:
void error(const QString &msg); void error(const QString &msg);
void avatarChanged(const QImage &img); void avatarChanged();
void nameEventSent(const QString &); void nameEventSent(const QString &);
void topicEventSent(); void topicEventSent();
}; };
@ -140,7 +140,7 @@ private:
void resetErrorLabel(); void resetErrorLabel();
void displayErrorMessage(const QString &msg); void displayErrorMessage(const QString &msg);
void setAvatar(const QImage &img); void setAvatar();
void setupEditButton(); void setupEditButton();
//! Retrieve the current room information from cache. //! Retrieve the current room information from cache.
void retrieveRoomInfo(); void retrieveRoomInfo();

View file

@ -1,58 +0,0 @@
#include <QTimer>
#include "UserMentions.h"
#include "timeline/TimelineItem.h"
using namespace dialogs;
UserMentions::UserMentions(QWidget *parent)
: QWidget{parent}
{
top_layout_ = new QVBoxLayout(this);
top_layout_->setSpacing(0);
top_layout_->setMargin(0);
scroll_area_ = new QScrollArea(this);
scroll_area_->setWidgetResizable(true);
scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scroll_widget_ = new QWidget(this);
scroll_widget_->setObjectName("scroll_widget");
// Height of the typing display.
QFont f;
f.setPointSizeF(f.pointSizeF() * 0.9);
const int bottomMargin = QFontMetrics(f).height() + 6;
scroll_layout_ = new QVBoxLayout(scroll_widget_);
scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin);
scroll_layout_->setSpacing(0);
scroll_layout_->setObjectName("timelinescrollarea");
scroll_area_->setWidget(scroll_widget_);
scroll_area_->setAlignment(Qt::AlignBottom);
top_layout_->addWidget(scroll_area_);
setLayout(top_layout_);
}
void
UserMentions::pushItem(const QString &event_id,
const QString &user_id,
const QString &body,
const QString &room_id)
{
TimelineItem *view_item = new TimelineItem(
mtx::events::MessageType::Text, user_id, body, true, room_id, scroll_widget_);
view_item->setEventId(event_id);
setUpdatesEnabled(false);
view_item->hide();
scroll_layout_->addWidget(view_item);
QTimer::singleShot(0, this, [view_item, this]() {
view_item->show();
view_item->adjustSize();
setUpdatesEnabled(true);
});
}

View file

@ -1,28 +0,0 @@
#pragma once
#include <QScrollArea>
#include <QScrollBar>
#include <QVBoxLayout>
#include <QWidget>
namespace dialogs {
class UserMentions : public QWidget
{
Q_OBJECT
public:
UserMentions(QWidget *parent = nullptr);
void pushItem(const QString &event_id,
const QString &user_id,
const QString &body,
const QString &room_id);
private:
QVBoxLayout *top_layout_;
QVBoxLayout *scroll_layout_;
QScrollArea *scroll_area_;
QWidget *scroll_widget_;
};
}

View file

@ -114,9 +114,8 @@ UserProfile::UserProfile(QWidget *parent)
btnLayout->setSpacing(8); btnLayout->setSpacing(8);
btnLayout->setMargin(0); btnLayout->setMargin(0);
avatar_ = new Avatar(this); avatar_ = new Avatar(this, 128);
avatar_->setLetter("X"); avatar_->setLetter("X");
avatar_->setSize(128);
QFont font; QFont font;
font.setPointSizeF(font.pointSizeF() * 2); font.setPointSizeF(font.pointSizeF() * 2);
@ -183,7 +182,7 @@ UserProfile::UserProfile(QWidget *parent)
qRegisterMetaType<std::vector<DeviceInfo>>(); qRegisterMetaType<std::vector<DeviceInfo>>();
auto closeShortcut = new QShortcut(QKeySequence(tr("ESC")), this); auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
connect(closeShortcut, &QShortcut::activated, this, &UserProfile::close); connect(closeShortcut, &QShortcut::activated, this, &UserProfile::close);
connect(okBtn, &QPushButton::clicked, this, &UserProfile::close); connect(okBtn, &QPushButton::clicked, this, &UserProfile::close);
} }
@ -210,8 +209,7 @@ UserProfile::init(const QString &userId, const QString &roomId)
displayNameLabel_->setText(displayName); displayNameLabel_->setText(displayName);
avatar_->setLetter(utils::firstChar(displayName)); avatar_->setLetter(utils::firstChar(displayName));
AvatarProvider::resolve( avatar_->setImage(roomId, userId);
roomId, userId, this, [this](const QImage &img) { avatar_->setImage(img); });
auto localUser = utils::localUser(); auto localUser = utils::localUser();

View file

@ -11,7 +11,7 @@ constexpr int PopupItemMargin = 3;
PopupItem::PopupItem(QWidget *parent) PopupItem::PopupItem(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, avatar_{new Avatar(this)} , avatar_{new Avatar(this, conf::popup::avatar)}
, hovering_{false} , hovering_{false}
{ {
setMouseTracking(true); setMouseTracking(true);
@ -40,7 +40,6 @@ UserItem::UserItem(QWidget *parent)
: PopupItem(parent) : PopupItem(parent)
{ {
userName_ = new QLabel("Placeholder", this); userName_ = new QLabel("Placeholder", this);
avatar_->setSize(conf::popup::avatar);
avatar_->setLetter("P"); avatar_->setLetter("P");
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addWidget(userName_, 1); topLayout_->addWidget(userName_, 1);
@ -52,7 +51,6 @@ UserItem::UserItem(QWidget *parent, const QString &user_id)
{ {
auto displayName = Cache::displayName(ChatPage::instance()->currentRoom(), userId_); auto displayName = Cache::displayName(ChatPage::instance()->currentRoom(), userId_);
avatar_->setSize(conf::popup::avatar);
avatar_->setLetter(utils::firstChar(displayName)); avatar_->setLetter(utils::firstChar(displayName));
// If it's a matrix id we use the second letter. // If it's a matrix id we use the second letter.
@ -87,16 +85,7 @@ UserItem::updateItem(const QString &user_id)
void void
UserItem::resolveAvatar(const QString &user_id) UserItem::resolveAvatar(const QString &user_id)
{ {
AvatarProvider::resolve( avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
ChatPage::instance()->currentRoom(), userId_, this, [this, user_id](const QImage &img) {
// The user on the widget when the avatar is resolved,
// might be different from the user that made the call.
if (user_id == userId_)
avatar_->setImage(img);
else
// We try to resolve the avatar again.
resolveAvatar(userId_);
});
} }
void void
@ -116,7 +105,6 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
auto name = QFontMetrics(QFont()).elidedText( auto name = QFontMetrics(QFont()).elidedText(
QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10); QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10);
avatar_->setSize(conf::popup::avatar + 6);
avatar_->setLetter(utils::firstChar(name)); avatar_->setLetter(utils::firstChar(name));
roomName_ = new QLabel(name, this); roomName_ = new QLabel(name, this);
@ -125,8 +113,7 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addWidget(roomName_, 1); topLayout_->addWidget(roomName_, 1);
if (!res.img.isNull()) avatar_->setImage(QString::fromStdString(res.info.avatar_url));
avatar_->setImage(res.img);
} }
void void
@ -141,10 +128,7 @@ RoomItem::updateItem(const RoomSearchResult &result)
roomName_->setText(name); roomName_->setText(name);
if (!result.img.isNull()) avatar_->setImage(QString::fromStdString(result.info.avatar_url));
avatar_->setImage(result.img);
else
avatar_->setLetter(utils::firstChar(name));
} }
void void

161
src/popups/UserMentions.cpp Normal file
View file

@ -0,0 +1,161 @@
#include <QPainter>
#include <QStyleOption>
#include <QTabWidget>
#include <QTimer>
#include "Cache.h"
#include "ChatPage.h"
#include "Logging.h"
#include "UserMentions.h"
#include "timeline/TimelineItem.h"
using namespace popups;
UserMentions::UserMentions(QWidget *parent)
: QWidget{parent}
{
setAttribute(Qt::WA_ShowWithoutActivating, true);
setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
tab_layout_ = new QTabWidget(this);
top_layout_ = new QVBoxLayout(this);
top_layout_->setSpacing(0);
top_layout_->setMargin(0);
local_scroll_area_ = new QScrollArea(this);
local_scroll_area_->setWidgetResizable(true);
local_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
local_scroll_widget_ = new QWidget(this);
local_scroll_widget_->setObjectName("local_scroll_widget");
all_scroll_area_ = new QScrollArea(this);
all_scroll_area_->setWidgetResizable(true);
all_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
all_scroll_widget_ = new QWidget(this);
all_scroll_widget_->setObjectName("all_scroll_widget");
// Height of the typing display.
QFont f;
f.setPointSizeF(f.pointSizeF() * 0.9);
const int bottomMargin = QFontMetrics(f).height() + 6;
local_scroll_layout_ = new QVBoxLayout(local_scroll_widget_);
local_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin);
local_scroll_layout_->setSpacing(0);
local_scroll_layout_->setObjectName("localscrollarea");
all_scroll_layout_ = new QVBoxLayout(all_scroll_widget_);
all_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin);
all_scroll_layout_->setSpacing(0);
all_scroll_layout_->setObjectName("allscrollarea");
local_scroll_area_->setWidget(local_scroll_widget_);
local_scroll_area_->setAlignment(Qt::AlignBottom);
all_scroll_area_->setWidget(all_scroll_widget_);
all_scroll_area_->setAlignment(Qt::AlignBottom);
tab_layout_->addTab(local_scroll_area_, tr("This Room"));
tab_layout_->addTab(all_scroll_area_, tr("All Rooms"));
top_layout_->addWidget(tab_layout_);
setLayout(top_layout_);
}
void
UserMentions::initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs)
{
nhlog::ui()->debug("Initializing " + std::to_string(notifs.size()) + " notifications.");
for (const auto &item : notifs) {
for (const auto notif : item.notifications) {
const auto event_id = QString::fromStdString(utils::event_id(notif.event));
try {
const auto room_id = QString::fromStdString(notif.room_id);
const auto user_id = utils::event_sender(notif.event);
const auto body = utils::event_body(notif.event);
pushItem(event_id,
user_id,
body,
room_id,
ChatPage::instance()->currentRoom());
} catch (const lmdb::error &e) {
nhlog::db()->warn("error while sending desktop notification: {}",
e.what());
}
}
}
}
void
UserMentions::showPopup()
{
for (auto widget : all_scroll_layout_->findChildren<QWidget *>()) {
delete widget;
}
for (auto widget : local_scroll_layout_->findChildren<QWidget *>()) {
delete widget;
}
auto notifs = cache::client()->getTimelineMentions();
initializeMentions(notifs);
show();
}
void
UserMentions::pushItem(const QString &event_id,
const QString &user_id,
const QString &body,
const QString &room_id,
const QString &current_room_id)
{
setUpdatesEnabled(false);
// Add to the 'all' section
TimelineItem *view_item = new TimelineItem(
mtx::events::MessageType::Text, user_id, body, true, room_id, all_scroll_widget_);
view_item->setEventId(event_id);
view_item->hide();
all_scroll_layout_->addWidget(view_item);
QTimer::singleShot(0, this, [view_item, this]() {
view_item->show();
view_item->adjustSize();
setUpdatesEnabled(true);
});
// if it matches the current room... add it to the current room as well.
if (QString::compare(room_id, current_room_id, Qt::CaseInsensitive) == 0) {
// Add to the 'local' section
TimelineItem *local_view_item = new TimelineItem(mtx::events::MessageType::Text,
user_id,
body,
true,
room_id,
local_scroll_widget_);
local_view_item->setEventId(event_id);
local_view_item->hide();
local_scroll_layout_->addWidget(local_view_item);
QTimer::singleShot(0, this, [local_view_item]() {
local_view_item->show();
local_view_item->adjustSize();
});
}
}
void
UserMentions::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

51
src/popups/UserMentions.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <mtx/responses.hpp>
#include <QApplication>
#include <QEvent>
#include <QMap>
#include <QPaintEvent>
#include <QScrollArea>
#include <QScrollBar>
#include <QString>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QWidget>
#include <Qt>
#include "Logging.h"
namespace popups {
class UserMentions : public QWidget
{
Q_OBJECT
public:
UserMentions(QWidget *parent = nullptr);
void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs);
void showPopup();
protected:
void paintEvent(QPaintEvent *) override;
private:
void pushItem(const QString &event_id,
const QString &user_id,
const QString &body,
const QString &room_id,
const QString &current_room_id);
QTabWidget *tab_layout_;
QVBoxLayout *top_layout_;
QVBoxLayout *local_scroll_layout_;
QVBoxLayout *all_scroll_layout_;
QScrollArea *local_scroll_area_;
QWidget *local_scroll_widget_;
QScrollArea *all_scroll_area_;
QWidget *all_scroll_widget_;
};
}

Binary file not shown.

View file

@ -282,6 +282,7 @@ TimelineItem::TimelineItem(mtx::events::MessageType ty,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(ty)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -325,8 +326,7 @@ TimelineItem::TimelineItem(mtx::events::MessageType ty,
generateBody(userid, displayName, formatted_body); generateBody(userid, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(userid);
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -341,6 +341,7 @@ TimelineItem::TimelineItem(ImageItem *image,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget{parent} : QWidget{parent}
, message_type_(mtx::events::MessageType::Image)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -356,6 +357,7 @@ TimelineItem::TimelineItem(FileItem *file,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget{parent} : QWidget{parent}
, message_type_(mtx::events::MessageType::File)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -369,6 +371,7 @@ TimelineItem::TimelineItem(AudioItem *audio,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget{parent} : QWidget{parent}
, message_type_(mtx::events::MessageType::Audio)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -382,6 +385,7 @@ TimelineItem::TimelineItem(VideoItem *video,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget{parent} : QWidget{parent}
, message_type_(mtx::events::MessageType::Video)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -395,6 +399,7 @@ TimelineItem::TimelineItem(ImageItem *image,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::Image)
, room_id_{room_id} , room_id_{room_id}
{ {
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Image>, ImageItem>( setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Image>, ImageItem>(
@ -426,6 +431,7 @@ TimelineItem::TimelineItem(FileItem *file,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::File)
, room_id_{room_id} , room_id_{room_id}
{ {
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::File>, FileItem>( setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::File>, FileItem>(
@ -440,6 +446,7 @@ TimelineItem::TimelineItem(AudioItem *audio,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::Audio)
, room_id_{room_id} , room_id_{room_id}
{ {
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Audio>, AudioItem>( setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Audio>, AudioItem>(
@ -454,6 +461,7 @@ TimelineItem::TimelineItem(VideoItem *video,
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::Video)
, room_id_{room_id} , room_id_{room_id}
{ {
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Video>, VideoItem>( setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Video>, VideoItem>(
@ -470,6 +478,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::Notice)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -499,8 +508,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice
generateBody(sender, displayName, formatted_body); generateBody(sender, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -517,6 +525,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote>
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::Emote)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -547,8 +556,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote>
generateBody(sender, displayName, formatted_body); generateBody(sender, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -565,6 +573,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text>
const QString &room_id, const QString &room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, message_type_(mtx::events::MessageType::Text)
, room_id_{room_id} , room_id_{room_id}
{ {
init(); init();
@ -595,8 +604,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text>
generateBody(sender, displayName, formatted_body); generateBody(sender, displayName, formatted_body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
generateBody(formatted_body); generateBody(formatted_body);
setupSimpleLayout(); setupSimpleLayout();
@ -781,9 +789,8 @@ TimelineItem::setupAvatarLayout(const QString &userName)
QFont f; QFont f;
f.setPointSizeF(f.pointSizeF()); f.setPointSizeF(f.pointSizeF());
userAvatar_ = new Avatar(this); userAvatar_ = new Avatar(this, QFontMetrics(f).height() * 2);
userAvatar_->setLetter(QChar(userName[0]).toUpper()); userAvatar_->setLetter(QChar(userName[0]).toUpper());
userAvatar_->setSize(QFontMetrics(f).height() * 2);
// TODO: The provided user name should be a UserId class // TODO: The provided user name should be a UserId class
if (userName[0] == '@' && userName.size() > 1) if (userName[0] == '@' && userName.size() > 1)
@ -810,12 +817,12 @@ TimelineItem::setupSimpleLayout()
} }
void void
TimelineItem::setUserAvatar(const QImage &avatar) TimelineItem::setUserAvatar(const QString &userid)
{ {
if (userAvatar_ == nullptr) if (userAvatar_ == nullptr)
return; return;
userAvatar_->setImage(avatar); userAvatar_->setImage(room_id_, userid);
} }
void void
@ -899,8 +906,7 @@ TimelineItem::addAvatar()
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(userid);
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} }
void void

View file

@ -215,7 +215,7 @@ public:
void setBackgroundColor(const QColor &color) { backgroundColor_ = color; } void setBackgroundColor(const QColor &color) { backgroundColor_ = color; }
QColor backgroundColor() const { return backgroundColor_; } QColor backgroundColor() const { return backgroundColor_; }
void setUserAvatar(const QImage &pixmap); void setUserAvatar(const QString &userid);
DescInfo descriptionMessage() const { return descriptionMsg_; } DescInfo descriptionMessage() const { return descriptionMsg_; }
QString eventId() const { return event_id_; } QString eventId() const { return event_id_; }
void setEventId(const QString &event_id) { event_id_ = event_id; } void setEventId(const QString &event_id) { event_id_ = event_id; }
@ -277,7 +277,7 @@ private:
QFutureWatcher<QString> *colorGenerating_; QFutureWatcher<QString> *colorGenerating_;
QString event_id_; QString event_id_;
mtx::events::MessageType message_type_; mtx::events::MessageType message_type_ = mtx::events::MessageType::Unknown;
QString room_id_; QString room_id_;
DescInfo descriptionMsg_; DescInfo descriptionMsg_;
@ -336,8 +336,7 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget, const QString &userid, bool
generateBody(userid, displayName, ""); generateBody(userid, displayName, "");
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(userid);
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
setupSimpleLayout(); setupSimpleLayout();
} }
@ -381,8 +380,7 @@ TimelineItem::setupWidgetLayout(Widget *widget, const Event &event, bool withSen
generateBody(sender, displayName, ""); generateBody(sender, displayName, "");
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
AvatarProvider::resolve( setUserAvatar(sender);
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else { } else {
setupSimpleLayout(); setupSimpleLayout();
} }

View file

@ -306,7 +306,10 @@ TimelineView::parseEncryptedEvent(const mtx::events::EncryptedEvent<mtx::events:
dummy.origin_server_ts = e.origin_server_ts; dummy.origin_server_ts = e.origin_server_ts;
dummy.event_id = e.event_id; dummy.event_id = e.event_id;
dummy.sender = e.sender; dummy.sender = e.sender;
dummy.content.body = "-- Encrypted Event (No keys found for decryption) --"; dummy.content.body =
tr("-- Encrypted Event (No keys found for decryption) --",
"Placeholder, when the message was not decrypted yet or can't be decrypted")
.toStdString();
try { try {
if (!cache::client()->inboundMegolmSessionExists(index)) { if (!cache::client()->inboundMegolmSessionExists(index)) {
@ -319,7 +322,10 @@ TimelineView::parseEncryptedEvent(const mtx::events::EncryptedEvent<mtx::events:
} }
} catch (const lmdb::error &e) { } catch (const lmdb::error &e) {
nhlog::db()->critical("failed to check megolm session's existence: {}", e.what()); nhlog::db()->critical("failed to check megolm session's existence: {}", e.what());
dummy.content.body = "-- Decryption Error (failed to communicate with DB) --"; dummy.content.body = tr("-- Decryption Error (failed to communicate with DB) --",
"Placeholder, when the message can't be decrypted, because "
"the DB access failed when trying to lookup the session.")
.toStdString();
return {dummy, false}; return {dummy, false};
} }
@ -335,7 +341,10 @@ TimelineView::parseEncryptedEvent(const mtx::events::EncryptedEvent<mtx::events:
index.sender_key, index.sender_key,
e.what()); e.what());
dummy.content.body = dummy.content.body =
"-- Decryption Error (failed to retrieve megolm keys from db) --"; tr("-- Decryption Error (failed to retrieve megolm keys from db) --",
"Placeholder, when the message can't be decrypted, because the DB access "
"failed.")
.toStdString();
return {dummy, false}; return {dummy, false};
} catch (const mtx::crypto::olm_exception &e) { } catch (const mtx::crypto::olm_exception &e) {
nhlog::crypto()->critical("failed to decrypt message with index ({}, {}, {}): {}", nhlog::crypto()->critical("failed to decrypt message with index ({}, {}, {}): {}",
@ -343,7 +352,12 @@ TimelineView::parseEncryptedEvent(const mtx::events::EncryptedEvent<mtx::events:
index.session_id, index.session_id,
index.sender_key, index.sender_key,
e.what()); e.what());
dummy.content.body = "-- Decryption Error (" + std::string(e.what()) + ") --"; dummy.content.body =
tr("-- Decryption Error (%1) --",
"Placeholder, when the message can't be decrypted. In this case, the Olm "
"decrytion returned an error, which is passed ad %1")
.arg(e.what())
.toStdString();
return {dummy, false}; return {dummy, false};
} }
@ -365,7 +379,11 @@ TimelineView::parseEncryptedEvent(const mtx::events::EncryptedEvent<mtx::events:
if (events.size() == 1) if (events.size() == 1)
return {events.at(0), true}; return {events.at(0), true};
dummy.content.body = "-- Encrypted Event (Unknown event type) --"; dummy.content.body =
tr("-- Encrypted Event (Unknown event type) --",
"Placeholder, when the message was decrypted, but we couldn't parse it, because "
"Nheko/mtxclient don't support that event type yet")
.toStdString();
return {dummy, false}; return {dummy, false};
} }

View file

@ -1,12 +1,14 @@
#include <QPainter> #include <QPainter>
#include <QSettings>
#include "AvatarProvider.h"
#include "Utils.h" #include "Utils.h"
#include "ui/Avatar.h" #include "ui/Avatar.h"
Avatar::Avatar(QWidget *parent) Avatar::Avatar(QWidget *parent, int size)
: QWidget(parent) : QWidget(parent)
, size_(size)
{ {
size_ = ui::AvatarSize;
type_ = ui::AvatarType::Letter; type_ = ui::AvatarType::Letter;
letter_ = "A"; letter_ = "A";
@ -60,21 +62,6 @@ Avatar::setBackgroundColor(const QColor &color)
background_color_ = color; background_color_ = color;
} }
void
Avatar::setSize(int size)
{
size_ = size;
if (!image_.isNull())
pixmap_ = utils::scaleImageToPixmap(image_, size_);
QFont _font(font());
_font.setPointSizeF(size_ * (ui::FontSize) / 40);
setFont(_font);
update();
}
void void
Avatar::setLetter(const QString &letter) Avatar::setLetter(const QString &letter)
{ {
@ -84,12 +71,23 @@ Avatar::setLetter(const QString &letter)
} }
void void
Avatar::setImage(const QImage &image) Avatar::setImage(const QString &avatar_url)
{ {
image_ = image; AvatarProvider::resolve(avatar_url, size_, this, [this](QPixmap pm) {
type_ = ui::AvatarType::Image; type_ = ui::AvatarType::Image;
pixmap_ = utils::scaleImageToPixmap(image_, size_); pixmap_ = pm;
update(); update();
});
}
void
Avatar::setImage(const QString &room, const QString &user)
{
AvatarProvider::resolve(room, user, size_, this, [this](QPixmap pm) {
type_ = ui::AvatarType::Image;
pixmap_ = pm;
update();
});
} }
void void
@ -103,6 +101,8 @@ Avatar::setIcon(const QIcon &icon)
void void
Avatar::paintEvent(QPaintEvent *) Avatar::paintEvent(QPaintEvent *)
{ {
bool rounded = QSettings().value("user/avatar/circles", true).toBool();
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
@ -116,7 +116,8 @@ Avatar::paintEvent(QPaintEvent *)
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
painter.setBrush(brush); painter.setBrush(brush);
painter.drawEllipse(r.center(), hs, hs); rounded ? painter.drawEllipse(r.center(), hs, hs)
: painter.drawRoundedRect(r, 3, 3);
} }
switch (type_) { switch (type_) {
@ -129,7 +130,10 @@ Avatar::paintEvent(QPaintEvent *)
} }
case ui::AvatarType::Image: { case ui::AvatarType::Image: {
QPainterPath ppath; QPainterPath ppath;
ppath.addEllipse(width() / 2 - hs, height() / 2 - hs, size_, size_);
rounded ? ppath.addEllipse(width() / 2 - hs, height() / 2 - hs, size_, size_)
: ppath.addRoundedRect(r, 3, 3);
painter.setClipPath(ppath); painter.setClipPath(ppath);
painter.drawPixmap(QRect(width() / 2 - hs, height() / 2 - hs, size_, size_), painter.drawPixmap(QRect(width() / 2 - hs, height() / 2 - hs, size_, size_),
pixmap_); pixmap_);

View file

@ -15,13 +15,13 @@ class Avatar : public QWidget
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
public: public:
explicit Avatar(QWidget *parent = 0); explicit Avatar(QWidget *parent = 0, int size = ui::AvatarSize);
void setBackgroundColor(const QColor &color); void setBackgroundColor(const QColor &color);
void setIcon(const QIcon &icon); void setIcon(const QIcon &icon);
void setImage(const QImage &image); void setImage(const QString &avatar_url);
void setImage(const QString &room, const QString &user);
void setLetter(const QString &letter); void setLetter(const QString &letter);
void setSize(int size);
void setTextColor(const QColor &color); void setTextColor(const QColor &color);
QColor backgroundColor() const; QColor backgroundColor() const;
@ -41,7 +41,6 @@ private:
QColor background_color_; QColor background_color_;
QColor text_color_; QColor text_color_;
QIcon icon_; QIcon icon_;
QImage image_;
QPixmap pixmap_; QPixmap pixmap_;
int size_; int size_;
}; };

View file

@ -2,6 +2,7 @@
#include "Config.h" #include "Config.h"
#include <QDateTime> #include <QDateTime>
#include <QLocale>
#include <QPainter> #include <QPainter>
#include <QPen> #include <QPen>
#include <QtGlobal> #include <QtGlobal>
@ -61,14 +62,14 @@ DateSeparator::DateSeparator(QDateTime datetime, QWidget *parent)
{ {
auto now = QDateTime::currentDateTime(); auto now = QDateTime::currentDateTime();
QString fmt; QString fmt = QLocale::system().dateFormat(QLocale::LongFormat);
if (now.date().year() != datetime.date().year()) if (now.date().year() == datetime.date().year()) {
fmt = QString("ddd d MMMM yy"); QRegularExpression rx("[^a-zA-Z]*y+[^a-zA-Z]*");
else fmt = fmt.remove(rx);
fmt = QString("ddd d MMMM"); }
msg_ = datetime.toString(fmt); msg_ = datetime.date().toString(fmt);
QFontMetrics fm{font()}; QFontMetrics fm{font()};
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)