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