From 12fff7408ea7539d778a641bbf1746693d30ee2a Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 27 Oct 2020 17:45:28 +0100 Subject: [PATCH 1/9] Optimize build --- CMakeLists.txt | 3 +- cmake/Hunter/config.cmake | 4 + io.github.NhekoReborn.Nheko.json | 2 +- src/Cache.cpp | 40 ++++++ src/Cache.h | 28 ++-- src/CacheCryptoStructs.h | 6 +- src/Cache_p.h | 7 +- src/CallManager.cpp | 5 +- src/CallManager.h | 2 +- src/ChatPage.cpp | 185 +++++++++++---------------- src/ChatPage.h | 37 +++--- src/CommunitiesList.cpp | 1 + src/DeviceVerificationFlow.cpp | 6 +- src/DeviceVerificationFlow.h | 1 + src/EventAccessors.cpp | 2 + src/MainWindow.cpp | 11 +- src/MxcImageProvider.cpp | 2 + src/Olm.cpp | 20 ++- src/Olm.h | 17 +-- src/RoomInfoListItem.h | 2 +- src/TextInputWidget.cpp | 4 +- src/UserSettingsPage.cpp | 17 +-- src/Utils.cpp | 2 +- src/dialogs/RoomSettings.cpp | 2 + src/main.cpp | 39 +++--- src/popups/SuggestionsPopup.cpp | 6 + src/popups/SuggestionsPopup.h | 3 +- src/popups/UserMentions.h | 2 +- src/timeline/EventStore.cpp | 3 + src/timeline/TimelineViewManager.cpp | 1 + src/timeline/TimelineViewManager.h | 5 +- src/ui/UserProfile.cpp | 4 +- src/ui/UserProfile.h | 6 - 33 files changed, 243 insertions(+), 232 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa839be..e5afb480 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,7 +340,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG 6432e89a3465e58ed838dd2abdcb0f91bd4f05b0 + GIT_TAG ba5af13e5378915ff99a2db6ccfb0e9ab9eba70a ) FetchContent_MakeAvailable(MatrixClient) else() @@ -600,6 +600,7 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") target_precompile_headers(nheko PRIVATE + ) endif() diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake index 7c53e0ea..4cdeee97 100644 --- a/cmake/Hunter/config.cmake +++ b/cmake/Hunter/config.cmake @@ -3,3 +3,7 @@ hunter_config( VERSION "1.70.0-p1" CMAKE_ARGS IOSTREAMS_NO_BZIP2=1 ) +hunter_config( + nlohmann_json + CMAKE_ARGS JSON_MultipleHeaders=ON +) diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json index c461ceaa..5738eb4f 100644 --- a/io.github.NhekoReborn.Nheko.json +++ b/io.github.NhekoReborn.Nheko.json @@ -146,7 +146,7 @@ "name": "mtxclient", "sources": [ { - "commit": "6432e89a3465e58ed838dd2abdcb0f91bd4f05b0", + "commit": "5af13e5378915ff99a2db6ccfb0e9ab9eba70a", "type": "git", "url": "https://github.com/Nheko-Reborn/mtxclient.git" } diff --git a/src/Cache.cpp b/src/Cache.cpp index 993fbfe7..f187af62 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -3376,6 +3376,46 @@ Cache::markUserKeysOutOfDate(lmdb::txn &txn, }); } +void +Cache::query_keys(const std::string &user_id, + std::function cb) +{ + auto cache_ = cache::userKeys(user_id); + + if (cache_.has_value()) { + if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) { + cb(cache_.value(), {}); + return; + } + } + + mtx::requests::QueryKeys req; + req.device_keys[user_id] = {}; + + std::string last_changed; + if (cache_) + last_changed = cache_->last_changed; + req.token = last_changed; + + http::client()->query_keys(req, + [cb, user_id, last_changed](const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn( + "failed to query device keys: {},{}", + err->matrix_error.errcode, + static_cast(err->status_code)); + cb({}, err); + return; + } + + cache::updateUserKeys(last_changed, res); + + auto keys = cache::userKeys(user_id); + cb(keys.value_or(UserKeyCache{}), err); + }); +} + void to_json(json &j, const VerificationCache &info) { diff --git a/src/Cache.h b/src/Cache.h index 98e6cb75..4c4f7071 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -28,11 +28,18 @@ #include #endif -#include +#include +#include +#include +#include #include "CacheCryptoStructs.h" #include "CacheStructs.h" +namespace mtx::responses { +struct Notifications; +} + namespace cache { void init(const QString &user_id); @@ -94,8 +101,6 @@ getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb); std::vector getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30); -void -saveState(const mtx::responses::Sync &res); bool isInitialized(); @@ -128,9 +133,6 @@ setCurrentFormat(); bool runMigrations(); -std::map -roomMessages(); - QMap getTimelineMentions(); @@ -182,22 +184,8 @@ saveImage(const QString &url, const QByteArray &data); RoomInfo singleRoomInfo(const std::string &room_id); -std::vector -roomsWithStateUpdates(const mtx::responses::Sync &res); -std::vector -roomsWithTagUpdates(const mtx::responses::Sync &res); std::map getRoomInfo(const std::vector &rooms); -inline std::map -roomUpdates(const mtx::responses::Sync &sync) -{ - return getRoomInfo(roomsWithStateUpdates(sync)); -} -inline std::map -roomTagUpdates(const mtx::responses::Sync &sync) -{ - return getRoomInfo(roomsWithTagUpdates(sync)); -} //! Calculates which the read status of a room. //! Whether all the events in the timeline have been read. diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h index a693e233..6256dcf9 100644 --- a/src/CacheCryptoStructs.h +++ b/src/CacheCryptoStructs.h @@ -3,10 +3,8 @@ #include #include -//#include - -#include -#include +#include +#include // Extra information associated with an outbound megolm session. struct OutboundGroupSessionData diff --git a/src/Cache_p.h b/src/Cache_p.h index a32793ea..96000ae3 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -33,8 +33,11 @@ #endif #include -#include +#include +#include +#include #include +#include #include "CacheCryptoStructs.h" #include "CacheStructs.h" @@ -65,6 +68,8 @@ public: void deleteUserKeys(lmdb::txn &txn, lmdb::dbi &db, const std::vector &user_ids); + void query_keys(const std::string &user_id, + std::function cb); // device & user verification cache VerificationStatus verificationStatus(const std::string &user_id); diff --git a/src/CallManager.cpp b/src/CallManager.cpp index b1d1a75a..eaf1a549 100644 --- a/src/CallManager.cpp +++ b/src/CallManager.cpp @@ -13,6 +13,7 @@ #include "MainWindow.h" #include "MatrixClient.h" #include "UserSettingsPage.h" +#include "Utils.h" #include "WebRTCSession.h" #include "dialogs/AcceptCall.h" @@ -33,8 +34,8 @@ std::vector getTurnURIs(const mtx::responses::TurnServer &turnServer); } -CallManager::CallManager(QSharedPointer userSettings) - : QObject() +CallManager::CallManager(QSharedPointer userSettings, QObject *parent) + : QObject(parent) , session_(WebRTCSession::instance()) , turnServerTimer_(this) , settings_(userSettings) diff --git a/src/CallManager.h b/src/CallManager.h index 640230a4..1964d76a 100644 --- a/src/CallManager.h +++ b/src/CallManager.h @@ -24,7 +24,7 @@ class CallManager : public QObject Q_OBJECT public: - CallManager(QSharedPointer); + CallManager(QSharedPointer, QObject *); void sendInvite(const QString &roomid); void hangUp( diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 235c5ea7..6e96234c 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -22,9 +22,12 @@ #include #include +#include + #include "AvatarProvider.h" #include "Cache.h" #include "Cache_p.h" +#include "CallManager.h" #include "ChatPage.h" #include "DeviceVerificationFlow.h" #include "EventAccessors.h" @@ -69,7 +72,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) , isConnected_(true) , userSettings_{userSettings} , notificationsManager(this) - , callManager_(userSettings) + , callManager_(new CallManager(userSettings, this)) { setObjectName("chatPage"); @@ -126,7 +129,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) contentLayout_->setSpacing(0); contentLayout_->setMargin(0); - view_manager_ = new TimelineViewManager(&callManager_, this); + view_manager_ = new TimelineViewManager(callManager_, this); contentLayout_->addWidget(view_manager_->getWidget()); @@ -434,8 +437,8 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) }); connect(text_input_, &TextInputWidget::callButtonPress, this, [this]() { - if (callManager_.onActiveCall()) { - callManager_.hangUp(); + if (callManager_->onActiveCall()) { + callManager_->hangUp(); } else { if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString()); roomInfo.member_count != 2) { @@ -454,7 +457,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) userSettings_, MainWindow::instance()); connect(dialog, &dialogs::PlaceCall::voice, this, [this]() { - callManager_.sendInvite(current_room_); + callManager_->sendInvite(current_room_); }); utils::centerWidget(dialog, MainWindow::instance()); dialog->show(); @@ -692,7 +695,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token) const bool isInitialized = cache::isInitialized(); const auto cacheVersion = cache::formatVersion(); - callManager_.refreshTurnServer(); + callManager_->refreshTurnServer(); if (!isInitialized) { cache::setCurrentFormat(); @@ -762,7 +765,7 @@ ChatPage::loadStateFromCache() cache::restoreSessions(); olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY); - emit initializeEmptyViews(cache::roomMessages()); + emit initializeEmptyViews(cache::client()->roomMessages()); emit initializeRoomList(cache::roomInfo()); emit initializeMentions(cache::getTimelineMentions()); emit syncTags(cache::roomInfo().toStdMap()); @@ -969,13 +972,64 @@ ChatPage::startInitialSync() opts.set_presence = currentPresence(); http::client()->sync( - opts, - std::bind( - &ChatPage::initialSyncHandler, this, std::placeholders::_1, std::placeholders::_2)); + opts, [this](const mtx::responses::Sync &res, mtx::http::RequestErr err) { + // TODO: Initial Sync should include mentions as well... + + if (err) { + const auto error = QString::fromStdString(err->matrix_error.error); + const auto msg = tr("Please try to login again: %1").arg(error); + const auto err_code = mtx::errors::to_string(err->matrix_error.errcode); + const int status_code = static_cast(err->status_code); + + nhlog::net()->error("initial sync error: {} {}", status_code, err_code); + + // non http related errors + if (status_code <= 0 || status_code >= 600) { + startInitialSync(); + return; + } + + switch (status_code) { + case 502: + case 504: + case 524: { + startInitialSync(); + return; + } + default: { + emit dropToLoginPageCb(msg); + return; + } + } + } + + nhlog::net()->info("initial sync completed"); + + try { + cache::client()->saveState(res); + + olm::handle_to_device_messages(res.to_device.events); + + emit initializeViews(std::move(res.rooms)); + emit initializeRoomList(cache::roomInfo()); + emit initializeMentions(cache::getTimelineMentions()); + + cache::calculateRoomReadStatus(); + emit syncTags(cache::roomInfo().toStdMap()); + } catch (const lmdb::error &e) { + nhlog::db()->error("failed to save state after initial sync: {}", + e.what()); + startInitialSync(); + return; + } + + emit trySyncCb(); + emit contentLoaded(); + }); } void -ChatPage::handleSyncResponse(mtx::responses::Sync res) +ChatPage::handleSyncResponse(const mtx::responses::Sync &res) { nhlog::net()->debug("sync completed: {}", res.next_batch); @@ -984,16 +1038,16 @@ ChatPage::handleSyncResponse(mtx::responses::Sync res) // TODO: fine grained error handling try { - cache::saveState(res); + cache::client()->saveState(res); olm::handle_to_device_messages(res.to_device.events); - auto updates = cache::roomUpdates(res); + auto updates = cache::getRoomInfo(cache::client()->roomsWithStateUpdates(res)); emit syncRoomlist(updates); emit syncUI(res.rooms); - emit syncTags(cache::roomTagUpdates(res)); + emit syncTags(cache::getRoomInfo(cache::client()->roomsWithTagUpdates(res))); // if we process a lot of syncs (1 every 200ms), this means we clean the // db every 100s @@ -1068,7 +1122,7 @@ ChatPage::joinRoom(const QString &room) const auto room_id = room.toStdString(); http::client()->join_room( - room_id, [this, room_id](const nlohmann::json &, mtx::http::RequestErr err) { + room_id, [this, room_id](const mtx::responses::RoomId &, mtx::http::RequestErr err) { if (err) { emit showNotification( tr("Failed to join room: %1") @@ -1114,7 +1168,8 @@ void ChatPage::leaveRoom(const QString &room_id) { http::client()->leave_room( - room_id.toStdString(), [this, room_id](const json &, mtx::http::RequestErr err) { + room_id.toStdString(), + [this, room_id](const mtx::responses::RoomId &, mtx::http::RequestErr err) { if (err) { emit showNotification( tr("Failed to leave room: %1") @@ -1289,62 +1344,6 @@ ChatPage::currentPresence() const } } -void -ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err) -{ - // TODO: Initial Sync should include mentions as well... - - if (err) { - const auto error = QString::fromStdString(err->matrix_error.error); - const auto msg = tr("Please try to login again: %1").arg(error); - const auto err_code = mtx::errors::to_string(err->matrix_error.errcode); - const int status_code = static_cast(err->status_code); - - nhlog::net()->error("initial sync error: {} {}", status_code, err_code); - - // non http related errors - if (status_code <= 0 || status_code >= 600) { - startInitialSync(); - return; - } - - switch (status_code) { - case 502: - case 504: - case 524: { - startInitialSync(); - return; - } - default: { - emit dropToLoginPageCb(msg); - return; - } - } - } - - nhlog::net()->info("initial sync completed"); - - try { - cache::saveState(res); - - olm::handle_to_device_messages(res.to_device.events); - - emit initializeViews(std::move(res.rooms)); - emit initializeRoomList(cache::roomInfo()); - emit initializeMentions(cache::getTimelineMentions()); - - cache::calculateRoomReadStatus(); - emit syncTags(cache::roomInfo().toStdMap()); - } catch (const lmdb::error &e) { - nhlog::db()->error("failed to save state after initial sync: {}", e.what()); - startInitialSync(); - return; - } - - emit trySyncCb(); - emit contentLoaded(); -} - void ChatPage::ensureOneTimeKeyCount(const std::map &counts) { @@ -1453,51 +1452,11 @@ ChatPage::initiateLogout() emit showOverlayProgressBar(); } -void -ChatPage::query_keys(const std::string &user_id, - std::function cb) -{ - auto cache_ = cache::userKeys(user_id); - - if (cache_.has_value()) { - if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) { - cb(cache_.value(), {}); - return; - } - } - - mtx::requests::QueryKeys req; - req.device_keys[user_id] = {}; - - std::string last_changed; - if (cache_) - last_changed = cache_->last_changed; - req.token = last_changed; - - http::client()->query_keys(req, - [cb, user_id, last_changed](const mtx::responses::QueryKeys &res, - mtx::http::RequestErr err) { - if (err) { - nhlog::net()->warn( - "failed to query device keys: {},{}", - err->matrix_error.errcode, - static_cast(err->status_code)); - cb({}, err); - return; - } - - cache::updateUserKeys(last_changed, res); - - auto keys = cache::userKeys(user_id); - cb(keys.value_or(UserKeyCache{}), err); - }); -} - template void ChatPage::connectCallMessage() { - connect(&callManager_, + connect(callManager_, qOverload(&CallManager::newMessage), view_manager_, qOverload(&TimelineViewManager::queueCallMessage)); diff --git a/src/ChatPage.h b/src/ChatPage.h index a29cea7b..da367c29 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -23,9 +23,10 @@ #include #include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -37,11 +38,8 @@ #include "CacheCryptoStructs.h" #include "CacheStructs.h" -#include "CallManager.h" #include "CommunitiesList.h" -#include "Utils.h" #include "notifications/Manager.h" -#include "popups/UserMentions.h" class OverlayModal; class QuickSwitcher; @@ -54,13 +52,25 @@ class UserInfoWidget; class UserSettings; class NotificationsManager; class TimelineModel; +class CallManager; constexpr int CONSENSUS_TIMEOUT = 1000; constexpr int SHOW_CONTENT_TIMEOUT = 3000; constexpr int TYPING_REFRESH_TIMEOUT = 10000; -namespace mtx::http { -using RequestErr = const std::optional &; +namespace mtx::requests { +struct CreateRoom; +} +namespace mtx::responses { +struct Notifications; +struct Sync; +struct Timeline; +struct Rooms; +struct LeftRoom; +} + +namespace popups { +class UserMentions; } class ChatPage : public QWidget @@ -89,8 +99,6 @@ public: //! Show the room/group list (if it was visible). void showSideBars(); void initiateLogout(); - void query_keys(const std::string &req, - std::function cb); void focusMessageInput(); QString status() const; @@ -145,7 +153,7 @@ signals: void trySyncCb(); void tryDelayedSyncCb(); void tryInitialSyncCb(); - void newSyncResponse(mtx::responses::Sync res); + void newSyncResponse(const mtx::responses::Sync &res); void leftRoom(const QString &room_id); void initializeRoomList(QMap); @@ -194,14 +202,11 @@ private slots: void joinRoom(const QString &room); void sendTypingNotifications(); - void handleSyncResponse(mtx::responses::Sync res); + void handleSyncResponse(const mtx::responses::Sync &res); private: static ChatPage *instance_; - //! Handler callback for initial sync. It doesn't run on the main thread so all - //! communication with the GUI should be done through signals. - void initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err); void startInitialSync(); void tryInitialSync(); void trySync(); @@ -276,7 +281,7 @@ private: QSharedPointer userSettings_; NotificationsManager notificationsManager; - CallManager callManager_; + CallManager *callManager_; }; template diff --git a/src/CommunitiesList.cpp b/src/CommunitiesList.cpp index 8a938646..c1d0706f 100644 --- a/src/CommunitiesList.cpp +++ b/src/CommunitiesList.cpp @@ -5,6 +5,7 @@ #include "Splitter.h" #include +#include #include diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index aa1a9607..509fce8c 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,8 +1,10 @@ #include "DeviceVerificationFlow.h" #include "Cache.h" +#include "Cache_p.h" #include "ChatPage.h" #include "Logging.h" +#include "Utils.h" #include "timeline/TimelineModel.h" #include @@ -39,7 +41,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, auto user_id = userID.toStdString(); this->toClient = mtx::identifiers::parse(user_id); - ChatPage::instance()->query_keys( + cache::client()->query_keys( user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) { if (err) { nhlog::net()->warn("failed to query device keys: {},{}", @@ -57,7 +59,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, this->their_keys = res; }); - ChatPage::instance()->query_keys( + cache::client()->query_keys( http::client()->user_id().to_string(), [this](const UserKeyCache &res, mtx::http::RequestErr err) { if (err) { diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index 70b5d9b3..d6e5411e 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -3,6 +3,7 @@ #include #include +#include #include "CacheCryptoStructs.h" #include "Logging.h" diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp index b62be9a5..3ae781f0 100644 --- a/src/EventAccessors.cpp +++ b/src/EventAccessors.cpp @@ -1,5 +1,7 @@ #include "EventAccessors.h" +#include + #include #include #include diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index c019b24b..37b54151 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "Cache.h" #include "ChatPage.h" @@ -54,8 +55,8 @@ MainWindow *MainWindow::instance_ = nullptr; MainWindow::MainWindow(const QString profile, QWidget *parent) - : QMainWindow(parent), - profile_{ profile } + : QMainWindow(parent) + , profile_{profile} { setWindowTitle(0); setObjectName("MainWindow"); @@ -104,8 +105,7 @@ MainWindow::MainWindow(const QString profile, QWidget *parent) connect(chat_page_, &ChatPage::closing, this, &MainWindow::showWelcomePage); connect( chat_page_, &ChatPage::showOverlayProgressBar, this, &MainWindow::showOverlayProgressBar); - connect( - chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle); + connect(chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle); connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int))); connect(chat_page_, &ChatPage::showLoginPage, this, [this](const QString &msg) { login_page_->loginError(msg); @@ -185,8 +185,7 @@ MainWindow::setWindowTitle(int notificationCount) QString name = "nheko"; if (!profile_.isEmpty()) name += " | " + profile_; - if (notificationCount > 0) - { + if (notificationCount > 0) { name.append(QString{" (%1)"}.arg(notificationCount)); } QMainWindow::setWindowTitle(name); diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp index b59fdff8..d6564277 100644 --- a/src/MxcImageProvider.cpp +++ b/src/MxcImageProvider.cpp @@ -1,5 +1,7 @@ #include "MxcImageProvider.h" +#include + #include "Cache.h" #include "Logging.h" #include "MatrixClient.h" diff --git a/src/Olm.cpp b/src/Olm.cpp index 6e68bd42..af8bb512 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -1,6 +1,7 @@ #include "Olm.h" #include +#include #include #include "Cache.h" @@ -20,6 +21,21 @@ auto client_ = std::make_unique(); } namespace olm { +void +from_json(const nlohmann::json &obj, OlmMessage &msg) +{ + if (obj.at("type") != "m.room.encrypted") + throw std::invalid_argument("invalid type for olm message"); + + if (obj.at("content").at("algorithm") != OLM_ALGO) + throw std::invalid_argument("invalid algorithm for olm message"); + + msg.sender = obj.at("sender"); + msg.sender_key = obj.at("content").at("sender_key"); + msg.ciphertext = obj.at("content") + .at("ciphertext") + .get>(); +} mtx::crypto::OlmClient * client() @@ -419,8 +435,8 @@ send_key_request_for(mtx::events::EncryptedEvent e, e.content.session_id); mtx::events::msg::KeyRequest request; - request.action = !cancel ? mtx::events::msg::RequestAction::Request - : mtx::events::msg::RequestAction::Cancellation; + request.action = !cancel ? mtx::events::msg::RequestAction::Request + : mtx::events::msg::RequestAction::Cancellation; request.algorithm = MEGOLM_ALGO; request.room_id = e.room_id; request.sender_key = e.content.sender_key; diff --git a/src/Olm.h b/src/Olm.h index 322affa1..3400f993 100644 --- a/src/Olm.h +++ b/src/Olm.h @@ -40,21 +40,8 @@ struct OlmMessage std::map ciphertext; }; -inline void -from_json(const nlohmann::json &obj, OlmMessage &msg) -{ - if (obj.at("type") != "m.room.encrypted") - throw std::invalid_argument("invalid type for olm message"); - - if (obj.at("content").at("algorithm") != OLM_ALGO) - throw std::invalid_argument("invalid algorithm for olm message"); - - msg.sender = obj.at("sender"); - msg.sender_key = obj.at("content").at("sender_key"); - msg.ciphertext = obj.at("content") - .at("ciphertext") - .get>(); -} +void +from_json(const nlohmann::json &obj, OlmMessage &msg); mtx::crypto::OlmClient * client(); diff --git a/src/RoomInfoListItem.h b/src/RoomInfoListItem.h index da5a1bc4..af919592 100644 --- a/src/RoomInfoListItem.h +++ b/src/RoomInfoListItem.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include "CacheStructs.h" #include "UserSettingsPage.h" diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp index e6a10f0a..13a7c6d0 100644 --- a/src/TextInputWidget.cpp +++ b/src/TextInputWidget.cpp @@ -453,8 +453,8 @@ FilteredTextEdit::completerRect() auto item_height = completer_->popup()->sizeHintForRow(0); auto max_height = item_height * completer_->maxVisibleItems(); auto height = (completer_->completionCount() > completer_->maxVisibleItems()) - ? max_height - : completer_->completionCount() * item_height; + ? max_height + : completer_->completionCount() * item_height; rect.setWidth(completer_->popup()->sizeHintForColumn(0)); rect.moveBottom(-height); return rect; diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index d4d5dcb9..78f9d546 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include #include #include -#include #include "Cache.h" #include "Config.h" @@ -450,7 +450,8 @@ UserSettingsPage::UserSettingsPage(QSharedPointer settings, QWidge auto versionInfo = new QLabel(QString("%1 | %2").arg(nheko::version).arg(nheko::build_os)); if (QCoreApplication::applicationName() != "nheko") - versionInfo->setText(versionInfo->text() + " | " + tr("profile: %1").arg(QCoreApplication::applicationName())); + versionInfo->setText(versionInfo->text() + " | " + + tr("profile: %1").arg(QCoreApplication::applicationName())); versionInfo->setTextInteractionFlags(Qt::TextBrowserInteraction); topBarLayout_ = new QHBoxLayout; @@ -904,11 +905,7 @@ UserSettingsPage::importSessionKeys() auto sessions = mtx::crypto::decrypt_exported_sessions(payload, password.toStdString()); cache::importSessionKeys(std::move(sessions)); - } catch (const mtx::crypto::sodium_exception &e) { - QMessageBox::warning(this, tr("Error"), e.what()); - } catch (const lmdb::error &e) { - QMessageBox::warning(this, tr("Error"), e.what()); - } catch (const nlohmann::json::exception &e) { + } catch (const std::exception &e) { QMessageBox::warning(this, tr("Error"), e.what()); } } @@ -956,11 +953,7 @@ UserSettingsPage::exportSessionKeys() QTextStream out(&file); out << prefix << newline << b64 << newline << suffix; file.close(); - } catch (const mtx::crypto::sodium_exception &e) { - QMessageBox::warning(this, tr("Error"), e.what()); - } catch (const lmdb::error &e) { - QMessageBox::warning(this, tr("Error"), e.what()); - } catch (const nlohmann::json::exception &e) { + } catch (const std::exception &e) { QMessageBox::warning(this, tr("Error"), e.what()); } } diff --git a/src/Utils.cpp b/src/Utils.cpp index 0bfc82c3..38dbba22 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -638,7 +638,7 @@ utils::luminance(const QColor &col) qreal lumRgb[3]; for (int i = 0; i < 3; i++) { - qreal v = colRgb[i] / 255.0; + qreal v = colRgb[i] / 255.0; v <= 0.03928 ? lumRgb[i] = v / 12.92 : lumRgb[i] = qPow((v + 0.055) / 1.055, 2.4); } diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp index 822b7218..5b7dc59a 100644 --- a/src/dialogs/RoomSettings.cpp +++ b/src/dialogs/RoomSettings.cpp @@ -17,6 +17,8 @@ #include #include "dialogs/RoomSettings.h" +#include +#include #include "Cache.h" #include "ChatPage.h" diff --git a/src/main.cpp b/src/main.cpp index 61cb4fbe..6fbccf5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,33 +107,28 @@ main(int argc, char *argv[]) // needed for settings so need to register before any settings are read to prevent warnings qRegisterMetaType(); - // This is some hacky programming, but it's necessary (AFAIK?) to get the unique config name parsed - // before the app name is set. + // This is some hacky programming, but it's necessary (AFAIK?) to get the unique config name + // parsed before the app name is set. QString appName{"nheko"}; - for (int i = 0; i < argc; ++i) - { - if (QString{argv[i]}.startsWith("--profile=")) - { + for (int i = 0; i < argc; ++i) { + if (QString{argv[i]}.startsWith("--profile=")) { QString q{argv[i]}; q.remove("--profile="); appName += "-" + q; - } - else if (QString{argv[i]}.startsWith("--p=")) - { + } else if (QString{argv[i]}.startsWith("--p=")) { QString q{argv[i]}; q.remove("-p="); appName += "-" + q; - } - else if (QString{argv[i]} == "--profile" || QString{argv[i]} == "-p") - { - if (i < argc -1) // if i is less than argc - 1, we still have a parameter left to process as the name + } else if (QString{argv[i]} == "--profile" || QString{argv[i]} == "-p") { + if (i < argc - 1) // if i is less than argc - 1, we still have a parameter + // left to process as the name { ++i; // the next arg is the name, so increment - appName += "-" + QString {argv[i]}; + appName += "-" + QString{argv[i]}; } } } - + QCoreApplication::setApplicationName(appName); QCoreApplication::setApplicationVersion(nheko::version); QCoreApplication::setOrganizationName("nheko"); @@ -168,11 +163,15 @@ main(int argc, char *argv[]) // This option is not actually parsed via Qt due to the need to parse it before the app // name is set. It only exists to keep Qt from complaining about the --profile/-p // option and thereby crashing the app. - QCommandLineOption configName(QStringList() << "p" << "profile", - QCoreApplication::tr("Create a unique profile, which allows you to log into several accounts at the same time and start multiple instances of nheko."), - QCoreApplication::tr("profile"), QCoreApplication::tr("profile name")); + QCommandLineOption configName( + QStringList() << "p" + << "profile", + QCoreApplication::tr("Create a unique profile, which allows you to log into several " + "accounts at the same time and start multiple instances of nheko."), + QCoreApplication::tr("profile"), + QCoreApplication::tr("profile name")); parser.addOption(configName); - + parser.process(app); app.setWindowIcon(QIcon(":/logos/nheko.png")); @@ -217,7 +216,7 @@ main(int argc, char *argv[]) appTranslator.load(QLocale(), "nheko", "_", ":/translations"); app.installTranslator(&appTranslator); - MainWindow w{ (appName == "nheko" ? "" : appName.remove("nheko-")) }; + MainWindow w{(appName == "nheko" ? "" : appName.remove("nheko-"))}; // Move the MainWindow to the center w.move(screenCenter(w.width(), w.height())); diff --git a/src/popups/SuggestionsPopup.cpp b/src/popups/SuggestionsPopup.cpp index 8f355b38..e84435b7 100644 --- a/src/popups/SuggestionsPopup.cpp +++ b/src/popups/SuggestionsPopup.cpp @@ -19,6 +19,12 @@ SuggestionsPopup::SuggestionsPopup(QWidget *parent) layout_->setSpacing(0); } +QString +SuggestionsPopup::displayName(QString room, QString user) +{ + return cache::displayName(room, user); +} + void SuggestionsPopup::addRooms(const std::vector &rooms) { diff --git a/src/popups/SuggestionsPopup.h b/src/popups/SuggestionsPopup.h index 73bfe6f7..c66f2903 100644 --- a/src/popups/SuggestionsPopup.h +++ b/src/popups/SuggestionsPopup.h @@ -22,7 +22,7 @@ public: const auto &widget = qobject_cast(item->widget()); emit itemSelected( - cache::displayName(ChatPage::instance()->currentRoom(), widget->selectedText())); + displayName(ChatPage::instance()->currentRoom(), widget->selectedText())); resetSelection(); } @@ -47,6 +47,7 @@ signals: void itemSelected(const QString &user); private: + QString displayName(QString roomid, QString userid); void hoverSelection(); void resetSelection() { selectedItem_ = -1; } void selectFirstItem() { selectedItem_ = 0; } diff --git a/src/popups/UserMentions.h b/src/popups/UserMentions.h index b7c4e51d..885fe67d 100644 --- a/src/popups/UserMentions.h +++ b/src/popups/UserMentions.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 38292f49..1cb729d3 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "Cache.h" #include "Cache_p.h" #include "ChatPage.h" @@ -10,6 +12,7 @@ #include "Logging.h" #include "MatrixClient.h" #include "Olm.h" +#include "Utils.h" Q_DECLARE_METATYPE(Reaction) diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 1e8ed243..e79b86d7 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -11,6 +11,7 @@ #include "ChatPage.h" #include "ColorImageProvider.h" #include "DelegateChooser.h" +#include "DeviceVerificationFlow.h" #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index b6f8b443..30bbc744 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -7,11 +7,11 @@ #include #include -#include +#include +#include #include "Cache.h" #include "CallManager.h" -#include "DeviceVerificationFlow.h" #include "Logging.h" #include "TimelineModel.h" #include "Utils.h" @@ -24,6 +24,7 @@ class BlurhashProvider; class ColorImageProvider; class UserSettings; class ChatPage; +class DeviceVerificationFlow; class TimelineViewManager : public QObject { diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 2bb0370f..974aa5cc 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -117,7 +117,7 @@ UserProfile::fetchDeviceList(const QString &userID) { auto localUser = utils::localUser(); - ChatPage::instance()->query_keys( + cache::client()->query_keys( userID.toStdString(), [other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys, mtx::http::RequestErr err) { @@ -129,7 +129,7 @@ UserProfile::fetchDeviceList(const QString &userID) } // Finding if the User is Verified or not based on the Signatures - ChatPage::instance()->query_keys( + cache::client()->query_keys( utils::localUser().toStdString(), [other_user_id, other_user_keys, this](const UserKeyCache &res, mtx::http::RequestErr err) { diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index 77b22323..62151266 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -5,8 +5,6 @@ #include #include -#include "MatrixClient.h" - namespace verification { Q_NAMESPACE @@ -116,8 +114,4 @@ private: bool isUserVerified = false; TimelineViewManager *manager; TimelineModel *model; - - void callback_fn(const mtx::responses::QueryKeys &res, - mtx::http::RequestErr err, - std::string user_id); }; From e939a6b396aafecf9cd17b79917637dcf8b6e5e9 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 27 Oct 2020 22:03:33 +0100 Subject: [PATCH 2/9] No roomid on leave --- src/ChatPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 6e96234c..fb34f91a 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -1169,7 +1169,7 @@ ChatPage::leaveRoom(const QString &room_id) { http::client()->leave_room( room_id.toStdString(), - [this, room_id](const mtx::responses::RoomId &, mtx::http::RequestErr err) { + [this, room_id](const mtx::responses::Empty &, mtx::http::RequestErr err) { if (err) { emit showNotification( tr("Failed to leave room: %1") From 2bac6d6c75f22416f61d0ef59951197df845e264 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 27 Oct 2020 22:16:59 +0100 Subject: [PATCH 3/9] Fix ambiguous namespace on gcc7 --- CMakeLists.txt | 2 +- io.github.NhekoReborn.Nheko.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5afb480..6b5bffd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,7 +340,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG ba5af13e5378915ff99a2db6ccfb0e9ab9eba70a + GIT_TAG ed6315563409ce9d47978ff2a2d771b863e375c5 ) FetchContent_MakeAvailable(MatrixClient) else() diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json index 5738eb4f..5dddeceb 100644 --- a/io.github.NhekoReborn.Nheko.json +++ b/io.github.NhekoReborn.Nheko.json @@ -146,7 +146,7 @@ "name": "mtxclient", "sources": [ { - "commit": "5af13e5378915ff99a2db6ccfb0e9ab9eba70a", + "commit": "ed6315563409ce9d47978ff2a2d771b863e375c5", "type": "git", "url": "https://github.com/Nheko-Reborn/mtxclient.git" } From 70f35de449fdcbca2a4ecd1100e1fa614ad069b4 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Wed, 28 Oct 2020 13:06:28 +0100 Subject: [PATCH 4/9] Don't pass around empty timeline --- src/Cache.cpp | 16 ++++++++-------- src/Cache_p.h | 3 +-- src/ChatPage.cpp | 2 +- src/ChatPage.h | 2 +- src/timeline/TimelineViewManager.cpp | 9 +++------ src/timeline/TimelineViewManager.h | 2 +- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index f187af62..b37f69b3 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1469,22 +1469,22 @@ Cache::getRoomInfo(const std::vector &rooms) return room_info; } -std::map -Cache::roomMessages() +std::vector +Cache::roomIds() { auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); - std::map msgs; + std::vector rooms; std::string room_id, unused; auto roomsCursor = lmdb::cursor::open(txn, roomsDb_); while (roomsCursor.get(room_id, unused, MDB_NEXT)) - msgs.emplace(QString::fromStdString(room_id), mtx::responses::Timeline()); + rooms.push_back(QString::fromStdString(room_id)); roomsCursor.close(); txn.commit(); - return msgs; + return rooms; } QMap @@ -3967,10 +3967,10 @@ setCurrentFormat() instance_->setCurrentFormat(); } -std::map -roomMessages() +std::vector +roomIds() { - return instance_->roomMessages(); + return instance_->roomIds(); } QMap diff --git a/src/Cache_p.h b/src/Cache_p.h index 96000ae3..05e13128 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -118,8 +118,7 @@ public: void setCurrentFormat(); bool runMigrations(); - std::map roomMessages(); - + std::vector roomIds(); QMap getTimelineMentions(); //! Retrieve all the user ids from a room. diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index fb34f91a..b587d521 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -765,7 +765,7 @@ ChatPage::loadStateFromCache() cache::restoreSessions(); olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY); - emit initializeEmptyViews(cache::client()->roomMessages()); + emit initializeEmptyViews(cache::client()->roomIds()); emit initializeRoomList(cache::roomInfo()); emit initializeMentions(cache::getTimelineMentions()); emit syncTags(cache::roomInfo().toStdMap()); diff --git a/src/ChatPage.h b/src/ChatPage.h index da367c29..0c12d89f 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -158,7 +158,7 @@ signals: void initializeRoomList(QMap); void initializeViews(const mtx::responses::Rooms &rooms); - void initializeEmptyViews(const std::map &msgs); + void initializeEmptyViews(const std::vector &roomIds); void initializeMentions(const QMap ¬ifs); void syncUI(const mtx::responses::Rooms &rooms); void syncRoomlist(const std::map &updates); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index e79b86d7..858d1090 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -451,13 +451,10 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s } void -TimelineViewManager::initWithMessages(const std::map &msgs) +TimelineViewManager::initWithMessages(const std::vector &roomIds) { - for (const auto &e : msgs) { - addRoom(e.first); - - models.value(e.first)->addEvents(e.second); - } + for (const auto &roomId : roomIds) + addRoom(roomId); } void diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 30bbc744..e42dd2f1 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -94,7 +94,7 @@ signals: public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids); void receivedSessionKey(const std::string &room_id, const std::string &session_id); - void initWithMessages(const std::map &msgs); + void initWithMessages(const std::vector &roomIds); void setHistoryView(const QString &room_id); void updateColorPalette(); From 775699d578be2ae545912fe0eb34ef004adb0071 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 28 Oct 2020 08:20:30 -0400 Subject: [PATCH 5/9] Translated using Weblate (Estonian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (411 of 411 strings) Co-authored-by: Priit Jõerüüt Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/et/ Translation: Nheko/nheko --- resources/langs/nheko_et.ts | 112 ++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/resources/langs/nheko_et.ts b/resources/langs/nheko_et.ts index b1f20985..b6041861 100644 --- a/resources/langs/nheko_et.ts +++ b/resources/langs/nheko_et.ts @@ -6,27 +6,27 @@ Initiating... - + Alustan kõnet… Calling... - + Helistan… Connecting... - + Ühendan… Unmute Mic - + Lülita mikrofon sisse Mute Mic - + Lülita mikrofon välja @@ -34,17 +34,17 @@ Awaiting Confirmation - + Ootan kinnitust Waiting for other side to complete verification. - + Ootan et teine osapool lõpetaks verifitseerimise. Cancel - + Katkesta @@ -260,22 +260,22 @@ Verification Code - + Verifitseerimise kood Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification! - + Palun võrdle järgmiseid numbreid. Sa peaks nägema samu numbreid mõlema osapoole seadmes. Kui nad omavahel ei klapi, siis palun vajuta verifitseerimise katkestamiseks „Nad ei klapi“ nuppu! They do not match! - + Nad ei klapi! They match! - + Mõlemad on samad! @@ -355,22 +355,22 @@ Verification Code - + Verifitseerimise kood Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification! - + Palun võrdle järgmiseid emojisid. Sa peaks nägema samu emojisid mõlema osapoole seadmes. Kui nad on erinevad, siis palun vajuta verifitseerimise katkestamiseks „Nad ei klapi“ nuppu! They do not match! - + Nad ei klapi! They match! - + Mõlemal pool on ühesugused emojid! @@ -430,28 +430,28 @@ Verification failed - + Verifitseerimine ei õnnestunud Other client does not support our verification protocol. - + Teise osapoole rakendus ei toeta siinkasutatavat verifitseerimisprotokolli. Key mismatch detected! - + Tuvastasin, et krüptovõtmed ei klapi omavahel! Device verification timed out. - + Seadme verifitseerimine aegus. Other party canceled the verification. - + Teine osapool katkestas verifitseerimise. @@ -646,7 +646,7 @@ Näiteks: https://server.minu:8787 Write a message... - Kirjuta sõnum… + Kirjuta sõnum… @@ -654,37 +654,37 @@ Näiteks: https://server.minu:8787 Send Device Verification Request - + Saada soov seadme verifitseerimiseks Recieved Device Verification Request - + Saabus soov seadme verifitseerimiseks To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device. - + Tagamaks et mitte ainsamgi kõrvaline osapoole ei saa sinu krüptitud suhtlust pealt kuulata, võid sa selle seadme verifitseerida. The device was requested to be verified - + Me soovime selle seadme verifitseerimist. Cancel - + Katkesta Deny - + Keeldu Start verification - + Alusta verifitseerimist @@ -705,17 +705,17 @@ Näiteks: https://server.minu:8787 Create a unique profile, which allows you to log into several accounts at the same time and start multiple instances of nheko. - + Loo unikaalne profiil, mis võimaldab sul logida samaaegselt sisse erinevatele kasutajakontodele ning käivitada mitu Nheko programmiakent. profile - + Profiil profile name - + Profiili nimi @@ -799,7 +799,7 @@ Näiteks: https://server.minu:8787 Close - Sulge + Sulge @@ -931,12 +931,12 @@ Näiteks: https://server.minu:8787 Successful Verification - + Verifitseerimine õnnestus Verification successful! Both sides verified their devices! - + Verifitseerimine õnnestus! Mõlema osapoole seadmed on nüüd verifitseeritud! @@ -1244,7 +1244,7 @@ Näiteks: https://server.minu:8787 No share room with this user found. Create an encrypted room with this user and try again. - + Selle kasutajaga pole sul ühist jututuba. Loo temaga krüptitud jututuba ja proovi uuesti. @@ -1252,38 +1252,38 @@ Näiteks: https://server.minu:8787 Back to room list - Tagasi jututubade loendisse + Tagasi jututubade loendisse No room selected - Jututuba on valimata + Jututuba on valimata Room options - Jututoa valikud + Jututoa valikud Invite users - Kutsu kasutajaid + Kutsu kasutajaid Members - Liikmed + Liikmed Leave room - Lahku jututoast + Lahku jututoast Settings - Seadistused + Seadistused @@ -1347,22 +1347,22 @@ Näiteks: https://server.minu:8787 Verify - + Verifitseeri Ban the user - + Sea kasutajale suhtluskeeld Start a private chat - + Alusta privaatset vestlust Kick the user - + Müksa kasutaja välja @@ -1390,7 +1390,7 @@ Näiteks: https://server.minu:8787 profile: %1 - + Profiil: %1 @@ -1546,12 +1546,12 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim Mobile mode - + Nutiseadme vaade Will prevent text selection in the timeline to make scrolling easier. - + Selleks, et ajajoone sirvimine oleks kiirem, ei ole teksti valimine lubatud. @@ -1636,12 +1636,12 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim Share keys with trusted users - + Jaga krüptovõtmeid usaldusväärsete kasutajatega Automatically replies to key requests from other users, if they are verified. - + Vasta verifitseeritud kasutajate krüptovõtmete päringutele automaatselt. @@ -1695,22 +1695,22 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim Waiting for other party - + Ootan teise osapoole järgi… Waiting for other side to accept the verification request. - + Ootan, et teine osapool nõustuks verifitseerimispäringuga… Waiting for other side to continue the verification request. - + Ootan, et teine osapool jätkaks verifitseerimist… Waiting for other side to complete the verification request. - + Ootan, et teine osapool lõpetaks verifitseerimise… From 6ef8e1729ddd829bb3360a9041b78242a4f07aa4 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 28 Oct 2020 08:20:30 -0400 Subject: [PATCH 6/9] Translated using Weblate (French) Currently translated at 100.0% (411 of 411 strings) Co-authored-by: Mayeul Cantan Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fr/ Translation: Nheko/nheko --- resources/langs/nheko_fr.ts | 200 ++++++++++++++++++------------------ 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index f8f8380b..337a13aa 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -6,27 +6,27 @@ Initiating... - + Initialisation… Calling... - + Appel… Connecting... - + Connexion… Unmute Mic - + Ne plus couper le micro Mute Mic - + Couper le micro @@ -34,17 +34,17 @@ Awaiting Confirmation - + Attente de confirmation Waiting for other side to complete verification. - + Attente de la vérification par le correspondant. Cancel - Annuler + Annuler @@ -86,12 +86,12 @@ Do you really want to invite %1 (%2)? - Voulez-vous vraiment inviter %1 (%2) ? + Voulez-vous vraiment inviter %1 (%2) ? Failed to invite %1 to %2: %3 - Échec de l'invitation de %1 dans %2 : %3 + Échec de l'invitation de %1 dans %2 : %3 @@ -101,7 +101,7 @@ Do you really want to kick %1 (%2)? - Voulez-vous vraiment expulser %1 (%2) ? + Voulez-vous vraiment expulser %1 (%2) ? @@ -121,7 +121,7 @@ Do you really want to ban %1 (%2)? - Voulez-vous vraiment bannir %1 (%2) ? + Voulez-vous vraiment bannir %1 (%2) ? @@ -141,12 +141,12 @@ Do you really want to unban %1 (%2)? - Voulez-vous vraiment annuler le bannissement de %1 (%2) ? + Voulez-vous vraiment annuler le bannissement de %1 (%2) ? Failed to unban %1 in %2: %3 - Échec de l'annulation du bannissement de %1 dans %2 : %3 + Échec de l'annulation du bannissement de %1 dans %2 : %3 @@ -161,7 +161,7 @@ Cache migration failed! - Échec de la migration du cache ! + Échec de la migration du cache ! @@ -186,18 +186,18 @@ Failed to setup encryption keys. Server response: %1 %2. Please try again later. - Échec de la configuration des clés de chiffrement. Réponse du serveur : %1 %2. Veuillez réessayer plus tard. + Échec de la configuration des clés de chiffrement. Réponse du serveur : %1 %2. Veuillez réessayer plus tard. Please try to login again: %1 - Veuillez vous reconnecter : %1 + Veuillez vous reconnecter : %1 Failed to join room: %1 - Impossible de rejoindre le salon : %1 + Impossible de rejoindre le salon : %1 @@ -207,17 +207,17 @@ Failed to remove invite: %1 - Impossible de supprimer l'invitation : %1 + Impossible de supprimer l'invitation : %1 Room creation failed: %1 - Échec de la création du salon : %1 + Échec de la création du salon : %1 Failed to leave room: %1 - Impossible de quitter le salon : %1 + Impossible de quitter le salon : %1 @@ -260,22 +260,22 @@ Verification Code - + Code de vérification Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification! - + Veuillez vérifier les chiffres suivants. Vous devriez voir les mêmes chiffres des deux côtés. Si ceux-ci diffèrent, veuillez choisir « Ils sont différents ! » pour annuler la vérification ! They do not match! - + Ils sont différents ! They match! - + Ils sont identiques ! @@ -355,22 +355,22 @@ Verification Code - + Code de vérification Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification! - + Veuillez vérifier les émoji suivantes. Vous devriez voir les mêmes émoji des deux côtés. Si celles-ci diffèrent, veuillez choisir « Elles sont différentes ! » pour annuler la vérification ! They do not match! - + Elles sont différentes ! They match! - + Elles sont identiques ! @@ -383,7 +383,7 @@ This message is not encrypted! - Ce message n'est pas chiffré ! + Ce message n'est pas chiffré ! @@ -417,12 +417,12 @@ -- Replay attack! This message index was reused! -- - -- Attaque par rejeu (replay attack) ! Cet index de message a été réutilisé ! -- + -- Attaque par rejeu (replay attack) ! Cet index de message a été réutilisé ! -- -- Message by unverified device! -- - -- Message d'un appareil non vérifié  -- + -- Message d'un appareil non vérifié  -- @@ -430,33 +430,33 @@ Verification failed - + Échec de la vérification Other client does not support our verification protocol. - + L'autre client ne supporte pas notre protocole de vérification. Key mismatch detected! - + Clés non correspondantes détectées ! Device verification timed out. - + Délai dépassé pour la vérification de l'appareil. Other party canceled the verification. - + Le correspondant a annulé la vérification. Close - Fermer + Fermer @@ -485,9 +485,9 @@ You can also put your homeserver address there, if your server doesn't support .well-known lookup. Example: @user:server.my If Nheko fails to discover your homeserver, it will show you a field to enter the server manually. - Votre nom de connexion. Un mxid doit commencer par un « @ » suivi de l'identifiant. L'identifiant doit être suivi du nom de serveur, séparé de celui-ci par « : ». + Votre nom de connexion. Un mxid doit commencer par un « @ » suivi de l'identifiant. L'identifiant doit être suivi du nom de serveur, séparé de celui-ci par « : ». Vous pouvez également spécifier l'adresse de votre serveur ici, si votre serveur ne supporte pas l'identification .well-known. -Exemple : @utilisateur :monserveur.example.com +Exemple : @utilisateur :monserveur.example.com Si Nheko n'arrive pas à trouver votre serveur, il vous proposera de l'indiquer manuellement. @@ -510,7 +510,7 @@ Si Nheko n'arrive pas à trouver votre serveur, il vous proposera de l&apos The address that can be used to contact you homeservers client API. Example: https://server.my:8787 L'adresse qui peut être utilisée pour joindre l'API client de votre serveur. -Exemple : https ://monserveur.example.com :8787 +Exemple : https ://monserveur.example.com :8787 @@ -588,7 +588,7 @@ Exemple : https ://monserveur.example.com :8787 room name changed to: %1 - nom du salon changé en : %1 + nom du salon changé en : %1 @@ -598,7 +598,7 @@ Exemple : https ://monserveur.example.com :8787 topic changed to: %1 - sujet changé pour : %1 + sujet changé pour : %1 @@ -608,7 +608,7 @@ Exemple : https ://monserveur.example.com :8787 %1 created and configured room: %2 - %1 a créé et configuré le salon : %2 + %1 a créé et configuré le salon : %2 @@ -646,7 +646,7 @@ Exemple : https ://monserveur.example.com :8787 Write a message... - Écrivez un message… + Écrivez un message… @@ -654,42 +654,42 @@ Exemple : https ://monserveur.example.com :8787 Send Device Verification Request - + Demander à vérifier l'appareil Recieved Device Verification Request - + Demande de vérification de l'appareil reçue To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device. - + Pour vous assurer qu'aucun utilisateur mal intentionné n'intercepte vos communications chiffrées, vous pouvez vérifier cet appareil. The device was requested to be verified - + La vérification de l'appareil a été demandée. Cancel - Annuler + Annuler Deny - + Refuser Start verification - + Démarrer la vérification Accept - Accepter + Accepter @@ -697,7 +697,7 @@ Exemple : https ://monserveur.example.com :8787 unimplemented event: - Évènement non implémenté : + Évènement non implémenté : @@ -705,17 +705,17 @@ Exemple : https ://monserveur.example.com :8787 Create a unique profile, which allows you to log into several accounts at the same time and start multiple instances of nheko. - + Créer un profil unique, vous permettant de vous connecter simultanément à plusieurs comptes et à lancer plusieurs instances de nheko. profile - + profil profile name - + nom du profil @@ -736,7 +736,7 @@ Exemple : https ://monserveur.example.com :8787 The username must not be empty, and must contain only the characters a-z, 0-9, ., _, =, -, and /. - Le nom d'utilisateur ne doit pas être vide, et ne peut contenir que les caractères a à z, 0 à 9, et « . _ = - / ». + Le nom d'utilisateur ne doit pas être vide, et ne peut contenir que les caractères a à z, 0 à 9, et « . _ = - / ». @@ -771,7 +771,7 @@ Exemple : https ://monserveur.example.com :8787 No supported registration flows! - Pas de méthode d'inscription supportée ! + Pas de méthode d'inscription supportée ! @@ -799,7 +799,7 @@ Exemple : https ://monserveur.example.com :8787 Close - Fermer + Fermer @@ -820,7 +820,7 @@ Exemple : https ://monserveur.example.com :8787 Tag room as: - Étiqueter le salon comme : + Étiqueter le salon comme : @@ -862,7 +862,7 @@ Exemple : https ://monserveur.example.com :8787 Tag: Tag name prompt - Étiquette : + Étiquette : @@ -931,17 +931,17 @@ Exemple : https ://monserveur.example.com :8787 Successful Verification - + Vérification réussie Verification successful! Both sides verified their devices! - + Vérification réussie ! Les deux côtés ont vérifié leur appareil ! Close - Fermer + Fermer @@ -998,14 +998,14 @@ Exemple : https ://monserveur.example.com :8787 Message redaction failed: %1 - Échec de la suppression du message : %1 + Échec de la suppression du message : %1 Failed to encrypt event, sending aborted! - Échec du chiffrement de l'évènement, envoi abandonné ! + Échec du chiffrement de l'évènement, envoi abandonné ! @@ -1160,12 +1160,12 @@ Exemple : https ://monserveur.example.com :8787 %1 left after having already left! This is a leave event after the user already left and shouldn't happen apart from state resets - %1 a quitté le salon après l'avoir déjà quitté ! + %1 a quitté le salon après l'avoir déjà quitté ! Reason: %1 - Raison : %1 + Raison : %1 @@ -1244,7 +1244,7 @@ Exemple : https ://monserveur.example.com :8787 No share room with this user found. Create an encrypted room with this user and try again. - + Aucun salon trouvé en commun avec cet utilisateur. Créez un salon chiffré avec cet utilisateur et réessayez. @@ -1252,38 +1252,38 @@ Exemple : https ://monserveur.example.com :8787 Back to room list - Revenir à la liste des salons + Revenir à la liste des salons No room selected - Pas de salon sélectionné + Pas de salon sélectionné Room options - Options du salon + Options du salon Invite users - Inviter des utilisateurs + Inviter des utilisateurs Members - Membres + Membres Leave room - Quitter le salon + Quitter le salon Settings - Paramètres + Paramètres @@ -1319,7 +1319,7 @@ Exemple : https ://monserveur.example.com :8787 Status: - Statut : + Statut : @@ -1347,22 +1347,22 @@ Exemple : https ://monserveur.example.com :8787 Verify - + Vérifier Ban the user - + Bannir l'utilisateur Start a private chat - + Créer une nouvelle discussion privée Kick the user - + Expulser l'utilisateur @@ -1390,7 +1390,7 @@ Exemple : https ://monserveur.example.com :8787 profile: %1 - + profil : %1 @@ -1547,12 +1547,12 @@ Cela met l'application en évidence dans la barre des tâches. Mobile mode - + Mode tactile Will prevent text selection in the timeline to make scrolling easier. - + Empêche la sélection du texte dans la discussion afin de rendre le défilement plus facile sur un écran tactile. @@ -1637,12 +1637,12 @@ Cela met l'application en évidence dans la barre des tâches. Share keys with trusted users - + Partager les clés avec les utilisateurs vérifiés Automatically replies to key requests from other users, if they are verified. - + Automatiquement répondre aux demandes de clés de déchiffrement des autres utilisateurs, si ceux-ci sont vérifiés. @@ -1672,7 +1672,7 @@ Cela met l'application en évidence dans la barre des tâches. Enter the passphrase to decrypt the file: - Entrez la clé secrète pour déchiffrer le fichier  : + Entrez la clé secrète pour déchiffrer le fichier  : @@ -1683,7 +1683,7 @@ Cela met l'application en évidence dans la barre des tâches. Enter passphrase to encrypt your session keys: - Entrez une clé secrète pour chiffrer vos clés de session  : + Entrez une clé secrète pour chiffrer vos clés de session  : @@ -1696,27 +1696,27 @@ Cela met l'application en évidence dans la barre des tâches. Waiting for other party - + En attente du correspondant… Waiting for other side to accept the verification request. - + Attente d'acceptation de la demande de vérification par le correspondant… Waiting for other side to continue the verification request. - + Attente de poursuite de la vérification par le correspondant… Waiting for other side to complete the verification request. - + Attente de finalisation de la vérification par le correspondant… Cancel - Annuler + Annuler @@ -2069,7 +2069,7 @@ attendant que la vérification des appareils soit opérationnelle. Failed to enable encryption: %1 - Échec de l'activation du chiffrement  : %1 + Échec de l'activation du chiffrement  : %1 @@ -2089,13 +2089,13 @@ attendant que la vérification des appareils soit opérationnelle. Error while reading file: %1 - Erreur lors de la lecture du fichier  : %1 + Erreur lors de la lecture du fichier  : %1 Failed to upload image: %s - Échec de l'envoi de l'image  : %s + Échec de l'envoi de l'image  : %s @@ -2128,7 +2128,7 @@ attendant que la vérification des appareils soit opérationnelle. Do you really want to invite %1 (%2) to a direct chat? - Voulez-vous vraiment inviter %1 (%2) dans un chat privé  ? + Voulez-vous vraiment inviter %1 (%2) dans un chat privé  ? @@ -2244,12 +2244,12 @@ attendant que la vérification des appareils soit opérationnelle. You: %1 - Vous  : %1 + Vous  : %1 %1: %2 - %1  : %2 + %1  : %2 From 3524e6f80df4220a58f92cdfe6b44f80c2b3d5b3 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 28 Oct 2020 08:20:30 -0400 Subject: [PATCH 7/9] Translated using Weblate (Finnish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 50.1% (206 of 411 strings) Co-authored-by: Priit Jõerüüt Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/fi/ Translation: Nheko/nheko --- resources/langs/nheko_fi.ts | 116 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/resources/langs/nheko_fi.ts b/resources/langs/nheko_fi.ts index bc44634c..f6586863 100644 --- a/resources/langs/nheko_fi.ts +++ b/resources/langs/nheko_fi.ts @@ -11,12 +11,12 @@ Calling... - + Soitetaan… Connecting... - + Yhdistetään… @@ -44,7 +44,7 @@ Cancel - Peruuta + Peruuta @@ -327,7 +327,7 @@ Activity - Aktiviteetti + Aktiviteetti @@ -337,17 +337,17 @@ Objects - Esineet + Esineet Symbols - Symbolit + Symbolit Flags - Liput + Liput @@ -392,27 +392,27 @@ -- Encrypted Event (No keys found for decryption) -- Placeholder, when the message was not decrypted yet or can't be decrypted. - -- Salattu viesti (salauksen purkuavaimia ei löydetty) -- + -- Salattu viesti (salauksen purkuavaimia ei löydetty) -- -- Decryption Error (failed to retrieve megolm keys from db) -- Placeholder, when the message can't be decrypted, because the DB access failed. - -- Virhe purkaessa salausta (megolm-avaimien hakeminen tietokannasta epäonnistui) -- + -- Virhe purkaessa salausta (megolm-avaimien hakeminen tietokannasta epäonnistui) -- -- Decryption Error (%1) -- Placeholder, when the message can't be decrypted. In this case, the Olm decrytion returned an error, which is passed as %1. - -- Virhe purkaessa salausta (%1) -- + -- Virhe purkaessa salausta (%1) -- -- 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. - -- Salattu viesti (tuntematon viestityyppi) -- + -- Salattu viesti (tuntematon viestityyppi) -- @@ -456,7 +456,7 @@ Close - Sulje + Sulje @@ -642,7 +642,7 @@ Example: https://server.my:8787 Write a message... - Kirjoita viesti… + Kirjoita viesti… @@ -670,7 +670,7 @@ Example: https://server.my:8787 Cancel - Peruuta + Peruuta @@ -685,7 +685,7 @@ Example: https://server.my:8787 Accept - Hyväksy + Hyväksy @@ -795,7 +795,7 @@ Example: https://server.my:8787 Close - Sulje + Sulje @@ -937,7 +937,7 @@ Example: https://server.my:8787 Close - Sulje + Sulje @@ -994,7 +994,7 @@ Example: https://server.my:8787 Message redaction failed: %1 - Viestin poisto epäonnistui: %1 + Viestin muokkaus epäonnistui: %1 @@ -1006,7 +1006,7 @@ Example: https://server.my:8787 Save image - Tallenna kuva + Tallenna kuva @@ -1202,7 +1202,7 @@ Example: https://server.my:8787 Read receipts - Lukukuittaukset + Lukukuittaukset @@ -1259,27 +1259,27 @@ Example: https://server.my:8787 Room options - Huonevaihtoehdot + Huoneen asetukset Invite users - Kutsu käyttäjiä + Kutsu käyttäjiä Members - Jäsenet + Jäsenet Leave room - Poistu huoneesta + Poistu huoneesta Settings - Asetukset + Asetukset @@ -1703,7 +1703,7 @@ This usually causes the application icon in the task bar to animate in some fash Cancel - Peruuta + Peruuta @@ -1742,12 +1742,12 @@ This usually causes the application icon in the task bar to animate in some fash Accept - Hyväksy + Hyväksy Reject - + Hylkää @@ -1803,12 +1803,12 @@ This usually causes the application icon in the task bar to animate in some fash Cancel - Peruuta + Peruuta Confirm - Vahvista + Vahvista @@ -1883,7 +1883,7 @@ This usually causes the application icon in the task bar to animate in some fash Cancel - Peruuta + Peruuta @@ -2069,12 +2069,12 @@ Median koko: %2 The selected file is not an image - + Valittu tiedosto ei ole kuva Error while reading file: %1 - + Virhe lukiessa tiedostoa: %1 @@ -2169,112 +2169,112 @@ Median koko: %2 You sent an audio clip - + Lähetit äänileikkeen %1 sent an audio clip - + %1 lähetti äänileikkeen You sent an image - + Lähetit kuvan %1 sent an image - + %1 lähetti kuvan You sent a file - + Lähetit tiedoston %1 sent a file - + %1 lähetti tiedoston You sent a video - + Lähetit videotiedoston %1 sent a video - + %1 lähetti videotiedoston You sent a sticker - + Lähetit tarran %1 sent a sticker - + %1 lähetti tarran You sent a notification - + Lähetit ilmoituksen %1 sent a notification - + %1 lähetti ilmoituksen You: %1 - + Sinä: %1 %1: %2 - + %1: %2 You sent an encrypted message - + Lähetit salatun viestin %1 sent an encrypted message - + %1 lähetti salatun viestin You placed a call - + Soitit puhelun %1 placed a call - + %1 soitti puhelun You answered a call - + Vastasit puheluun %1 answered a call - + %1 vastasi puheluun You ended a call - + Lopetit puhelun %1 ended a call - + %1 lopetti puhelun @@ -2282,12 +2282,12 @@ Median koko: %2 This Room - + Tämä huone All Rooms - + Kaikki huoneet @@ -2295,7 +2295,7 @@ Median koko: %2 Unknown Message Type - + Tuntematon viestityyppi From 1ba08f1ae7034ac4cdc50b5ae4444731ad200004 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 28 Oct 2020 08:20:30 -0400 Subject: [PATCH 8/9] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 31.3% (129 of 411 strings) Co-authored-by: Priit Jõerüüt Translate-URL: https://weblate.nheko.im/projects/nheko/nheko-master/ru/ Translation: Nheko/nheko --- resources/langs/nheko_ru.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/langs/nheko_ru.ts b/resources/langs/nheko_ru.ts index bc349646..cbe3fe07 100644 --- a/resources/langs/nheko_ru.ts +++ b/resources/langs/nheko_ru.ts @@ -642,7 +642,7 @@ Example: https://server.my:8787 Write a message... - Написать сообщение... + Написать сообщение… @@ -719,7 +719,7 @@ Example: https://server.my:8787 Search for a room... - Поиск комнаты... + Поиск комнаты… @@ -951,7 +951,7 @@ Example: https://server.my:8787 Write a message... - Написать сообщение... + Написать сообщение… @@ -986,7 +986,7 @@ Example: https://server.my:8787 Connection lost. Nheko is trying to re-connect... - Соединение потеряно. Nheko пытается переподключиться... + Соединение потеряно. Nheko пытается переподключиться… From 2143881997bc6389a5fa86bc34ca3a54b8826981 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Wed, 28 Oct 2020 14:53:11 +0100 Subject: [PATCH 9/9] Make back button bigger as it is hard to tap with your thumb --- resources/qml/TopBar.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index 181b9ba4..2015517c 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -35,6 +35,8 @@ Rectangle { Layout.row: 0 Layout.rowSpan: 2 Layout.alignment: Qt.AlignVCenter + width: avatarSize + height: avatarSize visible: TimelineManager.isNarrowView image: ":/icons/icons/ui/angle-pointing-to-left.png" ToolTip.visible: hovered