diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2fa839be5696360b950eececa347a45f97a2fe07..6b5bffd73a58c61a00966e338ea8094f305222b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -340,7 +340,7 @@ if(USE_BUNDLED_MTXCLIENT)
 	FetchContent_Declare(
 		MatrixClient
 		GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
-		GIT_TAG        6432e89a3465e58ed838dd2abdcb0f91bd4f05b0
+		GIT_TAG        ed6315563409ce9d47978ff2a2d771b863e375c5
 		)
 	FetchContent_MakeAvailable(MatrixClient)
 else()
@@ -600,6 +600,7 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
 target_precompile_headers(nheko
 	PRIVATE
 	  <string>
+	  <algorithm>
 	)
 endif()
 
diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake
index 7c53e0ea57096a3372bf3779dfdf86e8958e114e..4cdeee97ba09d684988a241aa5af943d5793550d 100644
--- a/cmake/Hunter/config.cmake
+++ b/cmake/Hunter/config.cmake
@@ -3,3 +3,7 @@ hunter_config(
     VERSION  "1.70.0-p1"
     CMAKE_ARGS IOSTREAMS_NO_BZIP2=1
 )
+hunter_config(
+    nlohmann_json
+    CMAKE_ARGS JSON_MultipleHeaders=ON
+)
diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json
index c461ceaaa4196377643031a7c7bd068ffbfd9e6c..5dddeceb45c5d5c3a4e1a0995ab2d0a408d32cb8 100644
--- a/io.github.NhekoReborn.Nheko.json
+++ b/io.github.NhekoReborn.Nheko.json
@@ -146,7 +146,7 @@
       "name": "mtxclient",
       "sources": [
         {
-          "commit": "6432e89a3465e58ed838dd2abdcb0f91bd4f05b0",
+          "commit": "ed6315563409ce9d47978ff2a2d771b863e375c5",
           "type": "git",
           "url": "https://github.com/Nheko-Reborn/mtxclient.git"
         }
diff --git a/resources/langs/nheko_et.ts b/resources/langs/nheko_et.ts
index b1f20985566b824aaa9d3a58ddfd510030be3031..b6041861344b6c3c16f31574ce97b06a6fca23b5 100644
--- a/resources/langs/nheko_et.ts
+++ b/resources/langs/nheko_et.ts
@@ -6,27 +6,27 @@
     <message>
         <location filename="../qml/ActiveCallBar.qml" line="+49"/>
         <source>Initiating...</source>
-        <translation type="unfinished"></translation>
+        <translation>Alustan kõnet…</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>Calling...</source>
-        <translation type="unfinished"></translation>
+        <translation>Helistan…</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>Connecting...</source>
-        <translation type="unfinished"></translation>
+        <translation>Ühendan…</translation>
     </message>
     <message>
         <location line="+48"/>
         <source>Unmute Mic</source>
-        <translation type="unfinished"></translation>
+        <translation>Lülita mikrofon sisse</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Mute Mic</source>
-        <translation type="unfinished"></translation>
+        <translation>Lülita mikrofon välja</translation>
     </message>
 </context>
 <context>
@@ -34,17 +34,17 @@
     <message>
         <location filename="../qml/device-verification/AwaitingVerificationConfirmation.qml" line="+7"/>
         <source>Awaiting Confirmation</source>
-        <translation type="unfinished"></translation>
+        <translation>Ootan kinnitust</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Waiting for other side to complete verification.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ootan et teine osapool lõpetaks verifitseerimise.</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Cancel</source>
-        <translation type="unfinished"></translation>
+        <translation>Katkesta</translation>
     </message>
 </context>
 <context>
@@ -260,22 +260,22 @@
     <message>
         <location filename="../qml/device-verification/DigitVerification.qml" line="+7"/>
         <source>Verification Code</source>
-        <translation type="unfinished"></translation>
+        <translation>Verifitseerimise kood</translation>
     </message>
     <message>
         <location line="+10"/>
         <source>Please verify the following digits. You should see the same numbers on both sides. If they differ, please press &apos;They do not match!&apos; to abort verification!</source>
-        <translation type="unfinished"></translation>
+        <translation>Palun võrdle järgmiseid numbreid. Sa peaks nägema samu numbreid mõlema osapoole seadmes. Kui nad omavahel ei klapi, siis palun vajuta verifitseerimise katkestamiseks „Nad ei klapi“ nuppu!</translation>
     </message>
     <message>
         <location line="+31"/>
         <source>They do not match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Nad ei klapi!</translation>
     </message>
     <message>
         <location line="+13"/>
         <source>They match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Mõlemad on samad!</translation>
     </message>
 </context>
 <context>
@@ -355,22 +355,22 @@
     <message>
         <location filename="../qml/device-verification/EmojiVerification.qml" line="+7"/>
         <source>Verification Code</source>
-        <translation type="unfinished"></translation>
+        <translation>Verifitseerimise kood</translation>
     </message>
     <message>
         <location line="+10"/>
         <source>Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press &apos;They do not match!&apos; to abort verification!</source>
-        <translation type="unfinished"></translation>
+        <translation>Palun võrdle järgmiseid emojisid. Sa peaks nägema samu emojisid mõlema osapoole seadmes. Kui nad on erinevad, siis palun vajuta verifitseerimise katkestamiseks „Nad ei klapi“ nuppu!</translation>
     </message>
     <message>
         <location line="+376"/>
         <source>They do not match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Nad ei klapi!</translation>
     </message>
     <message>
         <location line="+13"/>
         <source>They match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Mõlemal pool on ühesugused emojid!</translation>
     </message>
 </context>
 <context>
@@ -430,28 +430,28 @@
     <message>
         <location filename="../qml/device-verification/Failed.qml" line="+7"/>
         <source>Verification failed</source>
-        <translation type="unfinished"></translation>
+        <translation>Verifitseerimine ei õnnestunud</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Other client does not support our verification protocol.</source>
-        <translation type="unfinished"></translation>
+        <translation>Teise osapoole rakendus ei toeta siinkasutatavat verifitseerimisprotokolli.</translation>
     </message>
     <message>
         <location line="+4"/>
         <source>Key mismatch detected!</source>
-        <translation type="unfinished"></translation>
+        <translation>Tuvastasin, et krüptovõtmed ei klapi omavahel!</translation>
     </message>
     <message>
         <location line="+2"/>
         <location line="+4"/>
         <source>Device verification timed out.</source>
-        <translation type="unfinished"></translation>
+        <translation>Seadme verifitseerimine aegus.</translation>
     </message>
     <message>
         <location line="-2"/>
         <source>Other party canceled the verification.</source>
-        <translation type="unfinished"></translation>
+        <translation>Teine osapool katkestas verifitseerimise.</translation>
     </message>
     <message>
         <location line="+18"/>
@@ -646,7 +646,7 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../qml/MessageInput.qml" line="+47"/>
         <source>Write a message...</source>
-        <translation type="unfinished">Kirjuta sõnum…</translation>
+        <translation>Kirjuta sõnum…</translation>
     </message>
 </context>
 <context>
@@ -654,37 +654,37 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../qml/device-verification/NewVerificationRequest.qml" line="+7"/>
         <source>Send Device Verification Request</source>
-        <translation type="unfinished"></translation>
+        <translation>Saada soov seadme verifitseerimiseks</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Recieved Device Verification Request</source>
-        <translation type="unfinished"></translation>
+        <translation>Saabus soov seadme verifitseerimiseks</translation>
     </message>
     <message>
         <location line="+10"/>
         <source>To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device.</source>
-        <translation type="unfinished"></translation>
+        <translation>Tagamaks et mitte ainsamgi kõrvaline osapoole ei saa sinu krüptitud suhtlust pealt kuulata, võid sa selle seadme verifitseerida.</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>The device was requested to be verified</source>
-        <translation type="unfinished"></translation>
+        <translation>Me soovime selle seadme verifitseerimist.</translation>
     </message>
     <message>
         <location line="+8"/>
         <source>Cancel</source>
-        <translation type="unfinished"></translation>
+        <translation>Katkesta</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Deny</source>
-        <translation type="unfinished"></translation>
+        <translation>Keeldu</translation>
     </message>
     <message>
         <location line="+13"/>
         <source>Start verification</source>
-        <translation type="unfinished"></translation>
+        <translation>Alusta verifitseerimist</translation>
     </message>
     <message>
         <location line="+0"/>
@@ -705,17 +705,17 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../../src/main.cpp" line="+172"/>
         <source>Create a unique profile, which allows you to log into several accounts at the same time and start multiple instances of nheko.</source>
-        <translation type="unfinished"></translation>
+        <translation>Loo unikaalne profiil, mis võimaldab sul logida samaaegselt sisse erinevatele kasutajakontodele ning käivitada mitu Nheko programmiakent.</translation>
     </message>
     <message>
         <location line="+1"/>
         <source>profile</source>
-        <translation type="unfinished"></translation>
+        <translation>Profiil</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>profile name</source>
-        <translation type="unfinished"></translation>
+        <translation>Profiili nimi</translation>
     </message>
 </context>
 <context>
@@ -799,7 +799,7 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../qml/ReplyPopup.qml" line="+43"/>
         <source>Close</source>
-        <translation type="unfinished">Sulge</translation>
+        <translation>Sulge</translation>
     </message>
 </context>
 <context>
@@ -931,12 +931,12 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../qml/device-verification/Success.qml" line="+6"/>
         <source>Successful Verification</source>
-        <translation type="unfinished"></translation>
+        <translation>Verifitseerimine õnnestus</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Verification successful! Both sides verified their devices!</source>
-        <translation type="unfinished"></translation>
+        <translation>Verifitseerimine õnnestus! Mõlema osapoole seadmed on nüüd verifitseeritud!</translation>
     </message>
     <message>
         <location line="+12"/>
@@ -1244,7 +1244,7 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../../src/timeline/TimelineViewManager.cpp" line="+410"/>
         <source>No share room with this user found. Create an encrypted room with this user and try again.</source>
-        <translation type="unfinished"></translation>
+        <translation>Selle kasutajaga pole sul ühist jututuba. Loo temaga krüptitud jututuba ja proovi uuesti.</translation>
     </message>
 </context>
 <context>
@@ -1252,38 +1252,38 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../qml/TopBar.qml" line="+41"/>
         <source>Back to room list</source>
-        <translation type="unfinished">Tagasi jututubade loendisse</translation>
+        <translation>Tagasi jututubade loendisse</translation>
     </message>
     <message>
         <location line="+12"/>
         <location line="+15"/>
         <source>No room selected</source>
-        <translation type="unfinished">Jututuba on valimata</translation>
+        <translation>Jututuba on valimata</translation>
     </message>
     <message>
         <location line="+27"/>
         <source>Room options</source>
-        <translation type="unfinished">Jututoa valikud</translation>
+        <translation>Jututoa valikud</translation>
     </message>
     <message>
         <location line="+7"/>
         <source>Invite users</source>
-        <translation type="unfinished">Kutsu kasutajaid</translation>
+        <translation>Kutsu kasutajaid</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Members</source>
-        <translation type="unfinished">Liikmed</translation>
+        <translation>Liikmed</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Leave room</source>
-        <translation type="unfinished">Lahku jututoast</translation>
+        <translation>Lahku jututoast</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Settings</source>
-        <translation type="unfinished">Seadistused</translation>
+        <translation>Seadistused</translation>
     </message>
 </context>
 <context>
@@ -1347,22 +1347,22 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location filename="../qml/UserProfile.qml" line="+60"/>
         <source>Verify</source>
-        <translation type="unfinished"></translation>
+        <translation>Verifitseeri</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Ban the user</source>
-        <translation type="unfinished"></translation>
+        <translation>Sea kasutajale suhtluskeeld</translation>
     </message>
     <message>
         <location line="+20"/>
         <source>Start a private chat</source>
-        <translation type="unfinished"></translation>
+        <translation>Alusta privaatset vestlust</translation>
     </message>
     <message>
         <location line="+8"/>
         <source>Kick the user</source>
-        <translation type="unfinished"></translation>
+        <translation>Müksa kasutaja välja</translation>
     </message>
 </context>
 <context>
@@ -1390,7 +1390,7 @@ Näiteks: https://server.minu:8787</translation>
     <message>
         <location line="-149"/>
         <source>profile: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Profiil: %1</translation>
     </message>
     <message>
         <location line="+87"/>
@@ -1546,12 +1546,12 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim
     <message>
         <location line="+4"/>
         <source>Mobile mode</source>
-        <translation type="unfinished"></translation>
+        <translation>Nutiseadme vaade</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Will prevent text selection in the timeline to make scrolling easier.</source>
-        <translation type="unfinished"></translation>
+        <translation>Selleks, et ajajoone sirvimine oleks kiirem, ei ole teksti valimine lubatud.</translation>
     </message>
     <message>
         <location line="+2"/>
@@ -1636,12 +1636,12 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim
     <message>
         <location line="+18"/>
         <source>Share keys with trusted users</source>
-        <translation type="unfinished"></translation>
+        <translation>Jaga krüptovõtmeid usaldusväärsete kasutajatega</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Automatically replies to key requests from other users, if they are verified.</source>
-        <translation type="unfinished"></translation>
+        <translation>Vasta verifitseeritud kasutajate krüptovõtmete päringutele automaatselt.</translation>
     </message>
     <message>
         <location line="+185"/>
@@ -1695,22 +1695,22 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim
     <message>
         <location filename="../qml/device-verification/Waiting.qml" line="+7"/>
         <source>Waiting for other party</source>
-        <translation type="unfinished"></translation>
+        <translation>Ootan teise osapoole järgi…</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Waiting for other side to accept the verification request.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ootan, et teine osapool nõustuks verifitseerimispäringuga…</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Waiting for other side to continue the verification request.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ootan, et teine osapool jätkaks verifitseerimist…</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Waiting for other side to complete the verification request.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ootan, et teine osapool lõpetaks verifitseerimise…</translation>
     </message>
     <message>
         <location line="+15"/>
diff --git a/resources/langs/nheko_fi.ts b/resources/langs/nheko_fi.ts
index bc44634c24308540089d906232ad2a674403301e..f658686379a094d9338f8ad70b8312a48b7b3457 100644
--- a/resources/langs/nheko_fi.ts
+++ b/resources/langs/nheko_fi.ts
@@ -11,12 +11,12 @@
     <message>
         <location line="+3"/>
         <source>Calling...</source>
-        <translation type="unfinished"></translation>
+        <translation>Soitetaan…</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>Connecting...</source>
-        <translation type="unfinished"></translation>
+        <translation>Yhdistetään…</translation>
     </message>
     <message>
         <location line="+48"/>
@@ -44,7 +44,7 @@
     <message>
         <location line="+12"/>
         <source>Cancel</source>
-        <translation type="unfinished">Peruuta</translation>
+        <translation>Peruuta</translation>
     </message>
 </context>
 <context>
@@ -327,7 +327,7 @@
     <message>
         <location line="+2"/>
         <source>Activity</source>
-        <translation type="unfinished">Aktiviteetti</translation>
+        <translation>Aktiviteetti</translation>
     </message>
     <message>
         <location line="+2"/>
@@ -337,17 +337,17 @@
     <message>
         <location line="+2"/>
         <source>Objects</source>
-        <translation type="unfinished">Esineet</translation>
+        <translation>Esineet</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Symbols</source>
-        <translation type="unfinished">Symbolit</translation>
+        <translation>Symbolit</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Flags</source>
-        <translation type="unfinished">Liput</translation>
+        <translation>Liput</translation>
     </message>
 </context>
 <context>
@@ -392,27 +392,27 @@
         <location filename="../../src/timeline/EventStore.cpp" line="+519"/>
         <source>-- Encrypted Event (No keys found for decryption) --</source>
         <comment>Placeholder, when the message was not decrypted yet or can&apos;t be decrypted.</comment>
-        <translation type="unfinished">-- Salattu viesti (salauksen purkuavaimia ei löydetty) --</translation>
+        <translation>-- Salattu viesti (salauksen purkuavaimia ei löydetty) --</translation>
     </message>
     <message>
         <location line="+32"/>
         <location line="+62"/>
         <source>-- Decryption Error (failed to retrieve megolm keys from db) --</source>
         <comment>Placeholder, when the message can&apos;t be decrypted, because the DB access failed.</comment>
-        <translation type="unfinished">-- Virhe purkaessa salausta (megolm-avaimien hakeminen tietokannasta epäonnistui) --</translation>
+        <translation>-- Virhe purkaessa salausta (megolm-avaimien hakeminen tietokannasta epäonnistui) --</translation>
     </message>
     <message>
         <location line="-48"/>
         <location line="+61"/>
         <source>-- Decryption Error (%1) --</source>
         <comment>Placeholder, when the message can&apos;t be decrypted. In this case, the Olm decrytion returned an error, which is passed as %1.</comment>
-        <translation type="unfinished">-- Virhe purkaessa salausta (%1) --</translation>
+        <translation>-- Virhe purkaessa salausta (%1) --</translation>
     </message>
     <message>
         <location line="-51"/>
         <source>-- Encrypted Event (Unknown event type) --</source>
         <comment>Placeholder, when the message was decrypted, but we couldn&apos;t parse it, because Nheko/mtxclient don&apos;t support that event type yet.</comment>
-        <translation type="unfinished">-- Salattu viesti (tuntematon viestityyppi) --</translation>
+        <translation>-- Salattu viesti (tuntematon viestityyppi) --</translation>
     </message>
     <message>
         <location line="+13"/>
@@ -456,7 +456,7 @@
     <message>
         <location line="+18"/>
         <source>Close</source>
-        <translation type="unfinished">Sulje</translation>
+        <translation>Sulje</translation>
     </message>
 </context>
 <context>
@@ -642,7 +642,7 @@ Example: https://server.my:8787</source>
     <message>
         <location filename="../qml/MessageInput.qml" line="+47"/>
         <source>Write a message...</source>
-        <translation type="unfinished">Kirjoita viesti…</translation>
+        <translation>Kirjoita viesti…</translation>
     </message>
 </context>
 <context>
@@ -670,7 +670,7 @@ Example: https://server.my:8787</source>
     <message>
         <location line="+8"/>
         <source>Cancel</source>
-        <translation type="unfinished">Peruuta</translation>
+        <translation>Peruuta</translation>
     </message>
     <message>
         <location line="+0"/>
@@ -685,7 +685,7 @@ Example: https://server.my:8787</source>
     <message>
         <location line="+0"/>
         <source>Accept</source>
-        <translation type="unfinished">Hyväksy</translation>
+        <translation>Hyväksy</translation>
     </message>
 </context>
 <context>
@@ -795,7 +795,7 @@ Example: https://server.my:8787</source>
     <message>
         <location filename="../qml/ReplyPopup.qml" line="+43"/>
         <source>Close</source>
-        <translation type="unfinished">Sulje</translation>
+        <translation>Sulje</translation>
     </message>
 </context>
 <context>
@@ -937,7 +937,7 @@ Example: https://server.my:8787</source>
     <message>
         <location line="+12"/>
         <source>Close</source>
-        <translation type="unfinished">Sulje</translation>
+        <translation>Sulje</translation>
     </message>
 </context>
 <context>
@@ -994,7 +994,7 @@ Example: https://server.my:8787</source>
     <message>
         <location filename="../../src/timeline/TimelineModel.cpp" line="+853"/>
         <source>Message redaction failed: %1</source>
-        <translation type="unfinished">Viestin poisto epäonnistui: %1</translation>
+        <translation>Viestin muokkaus epäonnistui: %1</translation>
     </message>
     <message>
         <location line="+130"/>
@@ -1006,7 +1006,7 @@ Example: https://server.my:8787</source>
     <message>
         <location line="+156"/>
         <source>Save image</source>
-        <translation type="unfinished">Tallenna kuva</translation>
+        <translation>Tallenna kuva</translation>
     </message>
     <message>
         <location line="+2"/>
@@ -1202,7 +1202,7 @@ Example: https://server.my:8787</source>
     <message>
         <location line="+5"/>
         <source>Read receipts</source>
-        <translation type="unfinished">Lukukuittaukset</translation>
+        <translation>Lukukuittaukset</translation>
     </message>
     <message>
         <location line="+5"/>
@@ -1259,27 +1259,27 @@ Example: https://server.my:8787</source>
     <message>
         <location line="+27"/>
         <source>Room options</source>
-        <translation type="unfinished">Huonevaihtoehdot</translation>
+        <translation>Huoneen asetukset</translation>
     </message>
     <message>
         <location line="+7"/>
         <source>Invite users</source>
-        <translation type="unfinished">Kutsu käyttäjiä</translation>
+        <translation>Kutsu käyttäjiä</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Members</source>
-        <translation type="unfinished">Jäsenet</translation>
+        <translation>Jäsenet</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Leave room</source>
-        <translation type="unfinished">Poistu huoneesta</translation>
+        <translation>Poistu huoneesta</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Settings</source>
-        <translation type="unfinished">Asetukset</translation>
+        <translation>Asetukset</translation>
     </message>
 </context>
 <context>
@@ -1703,7 +1703,7 @@ This usually causes the application icon in the task bar to animate in some fash
     <message>
         <location line="+15"/>
         <source>Cancel</source>
-        <translation type="unfinished">Peruuta</translation>
+        <translation>Peruuta</translation>
     </message>
 </context>
 <context>
@@ -1742,12 +1742,12 @@ This usually causes the application icon in the task bar to animate in some fash
     <message>
         <location filename="../../src/dialogs/AcceptCall.cpp" line="+89"/>
         <source>Accept</source>
-        <translation type="unfinished">Hyväksy</translation>
+        <translation>Hyväksy</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Reject</source>
-        <translation type="unfinished"></translation>
+        <translation>Hylkää</translation>
     </message>
 </context>
 <context>
@@ -1803,12 +1803,12 @@ This usually causes the application icon in the task bar to animate in some fash
     <message>
         <location line="+1"/>
         <source>Cancel</source>
-        <translation type="unfinished">Peruuta</translation>
+        <translation>Peruuta</translation>
     </message>
     <message>
         <location line="+1"/>
         <source>Confirm</source>
-        <translation type="unfinished">Vahvista</translation>
+        <translation>Vahvista</translation>
     </message>
     <message>
         <location line="+12"/>
@@ -1883,7 +1883,7 @@ This usually causes the application icon in the task bar to animate in some fash
     <message>
         <location line="+4"/>
         <source>Cancel</source>
-        <translation type="unfinished">Peruuta</translation>
+        <translation>Peruuta</translation>
     </message>
 </context>
 <context>
@@ -2069,12 +2069,12 @@ Median koko: %2
     <message>
         <location line="+12"/>
         <source>The selected file is not an image</source>
-        <translation type="unfinished"></translation>
+        <translation>Valittu tiedosto ei ole kuva</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Error while reading file: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Virhe lukiessa tiedostoa: %1</translation>
     </message>
     <message>
         <location line="+35"/>
@@ -2169,112 +2169,112 @@ Median koko: %2
     <message>
         <location filename="../../src/Utils.h" line="+106"/>
         <source>You sent an audio clip</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit äänileikkeen</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent an audio clip</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti äänileikkeen</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You sent an image</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit kuvan</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent an image</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti kuvan</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You sent a file</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit tiedoston</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent a file</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti tiedoston</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You sent a video</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit videotiedoston</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent a video</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti videotiedoston</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You sent a sticker</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit tarran</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent a sticker</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti tarran</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You sent a notification</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit ilmoituksen</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent a notification</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti ilmoituksen</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Sinä: %1</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1: %2</source>
-        <translation type="unfinished"></translation>
+        <translation>%1: %2</translation>
     </message>
     <message>
         <location line="+7"/>
         <source>You sent an encrypted message</source>
-        <translation type="unfinished"></translation>
+        <translation>Lähetit salatun viestin</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 sent an encrypted message</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lähetti salatun viestin</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You placed a call</source>
-        <translation type="unfinished"></translation>
+        <translation>Soitit puhelun</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 placed a call</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 soitti puhelun</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You answered a call</source>
-        <translation type="unfinished"></translation>
+        <translation>Vastasit puheluun</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 answered a call</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 vastasi puheluun</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>You ended a call</source>
-        <translation type="unfinished"></translation>
+        <translation>Lopetit puhelun</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1 ended a call</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 lopetti puhelun</translation>
     </message>
 </context>
 <context>
@@ -2282,12 +2282,12 @@ Median koko: %2
     <message>
         <location filename="../../src/popups/UserMentions.cpp" line="+64"/>
         <source>This Room</source>
-        <translation type="unfinished"></translation>
+        <translation>Tämä huone</translation>
     </message>
     <message>
         <location line="+1"/>
         <source>All Rooms</source>
-        <translation type="unfinished"></translation>
+        <translation>Kaikki huoneet</translation>
     </message>
 </context>
 <context>
@@ -2295,7 +2295,7 @@ Median koko: %2
     <message>
         <location filename="../../src/Utils.h" line="+4"/>
         <source>Unknown Message Type</source>
-        <translation type="unfinished"></translation>
+        <translation>Tuntematon viestityyppi</translation>
     </message>
 </context>
 </TS>
diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts
index f8f8380b95a7880d9a2d6ec226b1c0dd469986a4..337a13aa55b1b698565bda64d0552f57386a6194 100644
--- a/resources/langs/nheko_fr.ts
+++ b/resources/langs/nheko_fr.ts
@@ -6,27 +6,27 @@
     <message>
         <location filename="../qml/ActiveCallBar.qml" line="+49"/>
         <source>Initiating...</source>
-        <translation type="unfinished"></translation>
+        <translation>Initialisation…</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>Calling...</source>
-        <translation type="unfinished"></translation>
+        <translation>Appel…</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>Connecting...</source>
-        <translation type="unfinished"></translation>
+        <translation>Connexion…</translation>
     </message>
     <message>
         <location line="+48"/>
         <source>Unmute Mic</source>
-        <translation type="unfinished"></translation>
+        <translation>Ne plus couper le micro</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Mute Mic</source>
-        <translation type="unfinished"></translation>
+        <translation>Couper le micro</translation>
     </message>
 </context>
 <context>
@@ -34,17 +34,17 @@
     <message>
         <location filename="../qml/device-verification/AwaitingVerificationConfirmation.qml" line="+7"/>
         <source>Awaiting Confirmation</source>
-        <translation type="unfinished"></translation>
+        <translation>Attente de confirmation</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Waiting for other side to complete verification.</source>
-        <translation type="unfinished"></translation>
+        <translation>Attente de la vérification par le correspondant.</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Cancel</source>
-        <translation type="unfinished">Annuler</translation>
+        <translation>Annuler</translation>
     </message>
 </context>
 <context>
@@ -86,12 +86,12 @@
     <message>
         <location line="+1"/>
         <source>Do you really want to invite %1 (%2)?</source>
-        <translation>Voulez-vous vraiment inviter %1 (%2)&#x202f;?</translation>
+        <translation>Voulez-vous vraiment inviter %1 (%2) ?</translation>
     </message>
     <message>
         <location line="+11"/>
         <source>Failed to invite %1 to %2: %3</source>
-        <translation>Échec de l&apos;invitation de %1 dans %2&#xa0;: %3</translation>
+        <translation>Échec de l&apos;invitation de %1 dans %2 : %3</translation>
     </message>
     <message>
         <location line="+15"/>
@@ -101,7 +101,7 @@
     <message>
         <location line="+1"/>
         <source>Do you really want to kick %1 (%2)?</source>
-        <translation>Voulez-vous vraiment expulser %1 (%2)&#x202f;?</translation>
+        <translation>Voulez-vous vraiment expulser %1 (%2) ?</translation>
     </message>
     <message>
         <location line="+11"/>
@@ -121,7 +121,7 @@
     <message>
         <location line="+1"/>
         <source>Do you really want to ban %1 (%2)?</source>
-        <translation>Voulez-vous vraiment bannir %1 (%2)&#x202f;?</translation>
+        <translation>Voulez-vous vraiment bannir %1 (%2) ?</translation>
     </message>
     <message>
         <location line="+11"/>
@@ -141,12 +141,12 @@
     <message>
         <location line="+1"/>
         <source>Do you really want to unban %1 (%2)?</source>
-        <translation>Voulez-vous vraiment annuler le bannissement de %1 (%2)&#x202f;?</translation>
+        <translation>Voulez-vous vraiment annuler le bannissement de %1 (%2) ?</translation>
     </message>
     <message>
         <location line="+11"/>
         <source>Failed to unban %1 in %2: %3</source>
-        <translation>Échec de l&apos;annulation du bannissement de %1 dans %2&#xa0;: %3</translation>
+        <translation>Échec de l&apos;annulation du bannissement de %1 dans %2 : %3</translation>
     </message>
     <message>
         <location line="+5"/>
@@ -161,7 +161,7 @@
     <message>
         <location line="+332"/>
         <source>Cache migration failed!</source>
-        <translation>Échec de la migration du cache&#x202f;!</translation>
+        <translation>Échec de la migration du cache !</translation>
     </message>
     <message>
         <location line="+13"/>
@@ -186,18 +186,18 @@
     <message>
         <location line="+165"/>
         <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source>
-        <translation>Échec de la configuration des clés de chiffrement. Réponse du serveur&#xa0;: %1 %2. Veuillez réessayer plus tard.</translation>
+        <translation>Échec de la configuration des clés de chiffrement. Réponse du serveur : %1 %2. Veuillez réessayer plus tard.</translation>
     </message>
     <message>
         <location line="+99"/>
         <location line="+257"/>
         <source>Please try to login again: %1</source>
-        <translation>Veuillez vous reconnecter&#xa0;: %1</translation>
+        <translation>Veuillez vous reconnecter : %1</translation>
     </message>
     <message>
         <location line="-225"/>
         <source>Failed to join room: %1</source>
-        <translation>Impossible de rejoindre le salon&#xa0;: %1</translation>
+        <translation>Impossible de rejoindre le salon : %1</translation>
     </message>
     <message>
         <location line="+5"/>
@@ -207,17 +207,17 @@
     <message>
         <location line="+6"/>
         <source>Failed to remove invite: %1</source>
-        <translation>Impossible de supprimer l&apos;invitation&#x202f;: %1</translation>
+        <translation>Impossible de supprimer l&apos;invitation : %1</translation>
     </message>
     <message>
         <location line="+19"/>
         <source>Room creation failed: %1</source>
-        <translation>Échec de la création du salon&#xa0;: %1</translation>
+        <translation>Échec de la création du salon : %1</translation>
     </message>
     <message>
         <location line="+16"/>
         <source>Failed to leave room: %1</source>
-        <translation>Impossible de quitter le salon&#xa0;: %1</translation>
+        <translation>Impossible de quitter le salon : %1</translation>
     </message>
 </context>
 <context>
@@ -260,22 +260,22 @@
     <message>
         <location filename="../qml/device-verification/DigitVerification.qml" line="+7"/>
         <source>Verification Code</source>
-        <translation type="unfinished"></translation>
+        <translation>Code de vérification</translation>
     </message>
     <message>
         <location line="+10"/>
         <source>Please verify the following digits. You should see the same numbers on both sides. If they differ, please press &apos;They do not match!&apos; to abort verification!</source>
-        <translation type="unfinished"></translation>
+        <translation>Veuillez vérifier les chiffres suivants. Vous devriez voir les mêmes chiffres des deux côtés. Si ceux-ci diffèrent, veuillez choisir « Ils sont différents ! » pour annuler la vérification !</translation>
     </message>
     <message>
         <location line="+31"/>
         <source>They do not match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Ils sont différents !</translation>
     </message>
     <message>
         <location line="+13"/>
         <source>They match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Ils sont identiques !</translation>
     </message>
 </context>
 <context>
@@ -355,22 +355,22 @@
     <message>
         <location filename="../qml/device-verification/EmojiVerification.qml" line="+7"/>
         <source>Verification Code</source>
-        <translation type="unfinished"></translation>
+        <translation>Code de vérification</translation>
     </message>
     <message>
         <location line="+10"/>
         <source>Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press &apos;They do not match!&apos; to abort verification!</source>
-        <translation type="unfinished"></translation>
+        <translation>Veuillez vérifier les émoji suivantes. Vous devriez voir les mêmes émoji des deux côtés. Si celles-ci diffèrent, veuillez choisir « Elles sont différentes ! » pour annuler la vérification !</translation>
     </message>
     <message>
         <location line="+376"/>
         <source>They do not match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Elles sont différentes !</translation>
     </message>
     <message>
         <location line="+13"/>
         <source>They match!</source>
-        <translation type="unfinished"></translation>
+        <translation>Elles sont identiques !</translation>
     </message>
 </context>
 <context>
@@ -383,7 +383,7 @@
     <message>
         <location line="+2"/>
         <source>This message is not encrypted!</source>
-        <translation>Ce message n&apos;est pas chiffré&#x202f;!</translation>
+        <translation>Ce message n&apos;est pas chiffré !</translation>
     </message>
 </context>
 <context>
@@ -417,12 +417,12 @@
     <message>
         <location line="+13"/>
         <source>-- Replay attack! This message index was reused! --</source>
-        <translation>-- Attaque par rejeu (replay attack)&#x202f;! Cet index de message a été réutilisé&#x202f;! --</translation>
+        <translation>-- Attaque par rejeu (replay attack) ! Cet index de message a été réutilisé ! --</translation>
     </message>
     <message>
         <location line="+7"/>
         <source>-- Message by unverified device! --</source>
-        <translation>-- Message d&apos;un appareil non vérifié&#x202f; --</translation>
+        <translation>-- Message d&apos;un appareil non vérifié  --</translation>
     </message>
 </context>
 <context>
@@ -430,33 +430,33 @@
     <message>
         <location filename="../qml/device-verification/Failed.qml" line="+7"/>
         <source>Verification failed</source>
-        <translation type="unfinished"></translation>
+        <translation>Échec de la vérification</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Other client does not support our verification protocol.</source>
-        <translation type="unfinished"></translation>
+        <translation>L&apos;autre client ne supporte pas notre protocole de vérification.</translation>
     </message>
     <message>
         <location line="+4"/>
         <source>Key mismatch detected!</source>
-        <translation type="unfinished"></translation>
+        <translation>Clés non correspondantes détectées !</translation>
     </message>
     <message>
         <location line="+2"/>
         <location line="+4"/>
         <source>Device verification timed out.</source>
-        <translation type="unfinished"></translation>
+        <translation>Délai dépassé pour la vérification de l&apos;appareil.</translation>
     </message>
     <message>
         <location line="-2"/>
         <source>Other party canceled the verification.</source>
-        <translation type="unfinished"></translation>
+        <translation>Le correspondant a annulé la vérification.</translation>
     </message>
     <message>
         <location line="+18"/>
         <source>Close</source>
-        <translation type="unfinished">Fermer</translation>
+        <translation>Fermer</translation>
     </message>
 </context>
 <context>
@@ -485,9 +485,9 @@
 You can also put your homeserver address there, if your server doesn&apos;t support .well-known lookup.
 Example: @user:server.my
 If Nheko fails to discover your homeserver, it will show you a field to enter the server manually.</source>
-        <translation>Votre nom de connexion. Un mxid doit commencer par un «&#x202f;@&#x202f;» suivi de l&apos;identifiant. L&apos;identifiant doit être suivi du nom de serveur, séparé de celui-ci par «&#x202f;:&#x202f;».
+        <translation>Votre nom de connexion. Un mxid doit commencer par un « @ » suivi de l&apos;identifiant. L&apos;identifiant doit être suivi du nom de serveur, séparé de celui-ci par « : ».
 Vous pouvez également spécifier l&apos;adresse de votre serveur ici, si votre serveur ne supporte pas l&apos;identification .well-known.
-Exemple&#x202f;: @utilisateur&#x202f;:monserveur.example.com
+Exemple : @utilisateur :monserveur.example.com
 Si Nheko n&apos;arrive pas à trouver votre serveur, il vous proposera de l&apos;indiquer manuellement.</translation>
     </message>
     <message>
@@ -510,7 +510,7 @@ Si Nheko n&apos;arrive pas à trouver votre serveur, il vous proposera de l&apos
         <source>The address that can be used to contact you homeservers client API.
 Example: https://server.my:8787</source>
         <translation>L&apos;adresse qui peut être utilisée pour joindre l&apos;API client de votre serveur.
-Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
+Exemple : https ://monserveur.example.com :8787</translation>
     </message>
     <message>
         <location line="+16"/>
@@ -588,7 +588,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+9"/>
         <source>room name changed to: %1</source>
-        <translation>nom du salon changé en&#xa0;: %1</translation>
+        <translation>nom du salon changé en : %1</translation>
     </message>
     <message>
         <location line="+0"/>
@@ -598,7 +598,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+9"/>
         <source>topic changed to: %1</source>
-        <translation>sujet changé pour&#xa0;: %1</translation>
+        <translation>sujet changé pour : %1</translation>
     </message>
     <message>
         <location line="+0"/>
@@ -608,7 +608,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+9"/>
         <source>%1 created and configured room: %2</source>
-        <translation>%1 a créé et configuré le salon&#xa0;: %2</translation>
+        <translation>%1 a créé et configuré le salon : %2</translation>
     </message>
     <message>
         <location line="+12"/>
@@ -646,7 +646,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/MessageInput.qml" line="+47"/>
         <source>Write a message...</source>
-        <translation type="unfinished">Écrivez un message…</translation>
+        <translation>Écrivez un message…</translation>
     </message>
 </context>
 <context>
@@ -654,42 +654,42 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/device-verification/NewVerificationRequest.qml" line="+7"/>
         <source>Send Device Verification Request</source>
-        <translation type="unfinished"></translation>
+        <translation>Demander à vérifier l&apos;appareil</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Recieved Device Verification Request</source>
-        <translation type="unfinished"></translation>
+        <translation>Demande de vérification de l&apos;appareil reçue</translation>
     </message>
     <message>
         <location line="+10"/>
         <source>To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device.</source>
-        <translation type="unfinished"></translation>
+        <translation>Pour vous assurer qu&apos;aucun utilisateur mal intentionné n&apos;intercepte vos communications chiffrées, vous pouvez vérifier cet appareil.</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>The device was requested to be verified</source>
-        <translation type="unfinished"></translation>
+        <translation>La vérification de l&apos;appareil a été demandée.</translation>
     </message>
     <message>
         <location line="+8"/>
         <source>Cancel</source>
-        <translation type="unfinished">Annuler</translation>
+        <translation>Annuler</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Deny</source>
-        <translation type="unfinished"></translation>
+        <translation>Refuser</translation>
     </message>
     <message>
         <location line="+13"/>
         <source>Start verification</source>
-        <translation type="unfinished"></translation>
+        <translation>Démarrer la vérification</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>Accept</source>
-        <translation type="unfinished">Accepter</translation>
+        <translation>Accepter</translation>
     </message>
 </context>
 <context>
@@ -697,7 +697,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/delegates/Placeholder.qml" line="+4"/>
         <source>unimplemented event: </source>
-        <translation>Évènement non implémenté&#xa0;: </translation>
+        <translation>Évènement non implémenté : </translation>
     </message>
 </context>
 <context>
@@ -705,17 +705,17 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../../src/main.cpp" line="+172"/>
         <source>Create a unique profile, which allows you to log into several accounts at the same time and start multiple instances of nheko.</source>
-        <translation type="unfinished"></translation>
+        <translation>Créer un profil unique, vous permettant de vous connecter simultanément à plusieurs comptes et à lancer plusieurs instances de nheko.</translation>
     </message>
     <message>
         <location line="+1"/>
         <source>profile</source>
-        <translation type="unfinished"></translation>
+        <translation>profil</translation>
     </message>
     <message>
         <location line="+0"/>
         <source>profile name</source>
-        <translation type="unfinished"></translation>
+        <translation>nom du profil</translation>
     </message>
 </context>
 <context>
@@ -736,7 +736,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+3"/>
         <source>The username must not be empty, and must contain only the characters a-z, 0-9, ., _, =, -, and /.</source>
-        <translation>Le nom d&apos;utilisateur ne doit pas être vide, et ne peut contenir que les caractères a à z, 0 à 9, et «&#x202f;. _ = - /&#x202f;».</translation>
+        <translation>Le nom d&apos;utilisateur ne doit pas être vide, et ne peut contenir que les caractères a à z, 0 à 9, et « . _ = - / ».</translation>
     </message>
     <message>
         <location line="+4"/>
@@ -771,7 +771,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+55"/>
         <source>No supported registration flows!</source>
-        <translation>Pas de méthode d&apos;inscription supportée&#xa0;!</translation>
+        <translation>Pas de méthode d&apos;inscription supportée !</translation>
     </message>
     <message>
         <location line="+135"/>
@@ -799,7 +799,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/ReplyPopup.qml" line="+43"/>
         <source>Close</source>
-        <translation type="unfinished">Fermer</translation>
+        <translation>Fermer</translation>
     </message>
 </context>
 <context>
@@ -820,7 +820,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+7"/>
         <source>Tag room as:</source>
-        <translation>Étiqueter le salon comme&#xa0;:</translation>
+        <translation>Étiqueter le salon comme :</translation>
     </message>
     <message>
         <location line="+18"/>
@@ -862,7 +862,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
         <location line="+1"/>
         <source>Tag:</source>
         <comment>Tag name prompt</comment>
-        <translation>Étiquette&#xa0;:</translation>
+        <translation>Étiquette :</translation>
     </message>
     <message>
         <location line="+169"/>
@@ -931,17 +931,17 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/device-verification/Success.qml" line="+6"/>
         <source>Successful Verification</source>
-        <translation type="unfinished"></translation>
+        <translation>Vérification réussie</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Verification successful! Both sides verified their devices!</source>
-        <translation type="unfinished"></translation>
+        <translation>Vérification réussie ! Les deux côtés ont vérifié leur appareil !</translation>
     </message>
     <message>
         <location line="+12"/>
         <source>Close</source>
-        <translation type="unfinished">Fermer</translation>
+        <translation>Fermer</translation>
     </message>
 </context>
 <context>
@@ -998,14 +998,14 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../../src/timeline/TimelineModel.cpp" line="+853"/>
         <source>Message redaction failed: %1</source>
-        <translation>Échec de la suppression du message&#xa0;: %1</translation>
+        <translation>Échec de la suppression du message : %1</translation>
     </message>
     <message>
         <location line="+130"/>
         <location line="+8"/>
         <location line="+5"/>
         <source>Failed to encrypt event, sending aborted!</source>
-        <translation>Échec du chiffrement de l&apos;évènement, envoi abandonné&#x202f;!</translation>
+        <translation>Échec du chiffrement de l&apos;évènement, envoi abandonné !</translation>
     </message>
     <message>
         <location line="+156"/>
@@ -1160,12 +1160,12 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
         <location line="+2"/>
         <source>%1 left after having already left!</source>
         <comment>This is a leave event after the user already left and shouldn&apos;t happen apart from state resets</comment>
-        <translation>%1 a quitté le salon après l&apos;avoir déjà quitté&#x202f;!</translation>
+        <translation>%1 a quitté le salon après l&apos;avoir déjà quitté !</translation>
     </message>
     <message>
         <location line="+15"/>
         <source> Reason: %1</source>
-        <translation>Raison&#xa0;: %1</translation>
+        <translation>Raison : %1</translation>
     </message>
     <message>
         <location line="-5"/>
@@ -1244,7 +1244,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../../src/timeline/TimelineViewManager.cpp" line="+410"/>
         <source>No share room with this user found. Create an encrypted room with this user and try again.</source>
-        <translation type="unfinished"></translation>
+        <translation>Aucun salon trouvé en commun avec cet utilisateur. Créez un salon chiffré avec cet utilisateur et réessayez.</translation>
     </message>
 </context>
 <context>
@@ -1252,38 +1252,38 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/TopBar.qml" line="+41"/>
         <source>Back to room list</source>
-        <translation type="unfinished">Revenir à la liste des salons</translation>
+        <translation>Revenir à la liste des salons</translation>
     </message>
     <message>
         <location line="+12"/>
         <location line="+15"/>
         <source>No room selected</source>
-        <translation type="unfinished">Pas de salon sélectionné</translation>
+        <translation>Pas de salon sélectionné</translation>
     </message>
     <message>
         <location line="+27"/>
         <source>Room options</source>
-        <translation type="unfinished">Options du salon</translation>
+        <translation>Options du salon</translation>
     </message>
     <message>
         <location line="+7"/>
         <source>Invite users</source>
-        <translation type="unfinished">Inviter des utilisateurs</translation>
+        <translation>Inviter des utilisateurs</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Members</source>
-        <translation type="unfinished">Membres</translation>
+        <translation>Membres</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Leave room</source>
-        <translation type="unfinished">Quitter le salon</translation>
+        <translation>Quitter le salon</translation>
     </message>
     <message>
         <location line="+5"/>
         <source>Settings</source>
-        <translation type="unfinished">Paramètres</translation>
+        <translation>Paramètres</translation>
     </message>
 </context>
 <context>
@@ -1319,7 +1319,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="+1"/>
         <source>Status:</source>
-        <translation>Statut&#xa0;:</translation>
+        <translation>Statut :</translation>
     </message>
     <message>
         <location line="+9"/>
@@ -1347,22 +1347,22 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location filename="../qml/UserProfile.qml" line="+60"/>
         <source>Verify</source>
-        <translation type="unfinished"></translation>
+        <translation>Vérifier</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Ban the user</source>
-        <translation type="unfinished"></translation>
+        <translation>Bannir l&apos;utilisateur</translation>
     </message>
     <message>
         <location line="+20"/>
         <source>Start a private chat</source>
-        <translation type="unfinished"></translation>
+        <translation>Créer une nouvelle discussion privée</translation>
     </message>
     <message>
         <location line="+8"/>
         <source>Kick the user</source>
-        <translation type="unfinished"></translation>
+        <translation>Expulser l&apos;utilisateur</translation>
     </message>
 </context>
 <context>
@@ -1390,7 +1390,7 @@ Exemple&#xa0;: https&#x202f;://monserveur.example.com&#x202f;:8787</translation>
     <message>
         <location line="-149"/>
         <source>profile: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>profil : %1</translation>
     </message>
     <message>
         <location line="+87"/>
@@ -1547,12 +1547,12 @@ Cela met l&apos;application en évidence dans la barre des tâches.</translation
     <message>
         <location line="+4"/>
         <source>Mobile mode</source>
-        <translation type="unfinished"></translation>
+        <translation>Mode tactile</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Will prevent text selection in the timeline to make scrolling easier.</source>
-        <translation type="unfinished"></translation>
+        <translation>Empêche la sélection du texte dans la discussion afin de rendre le défilement plus facile sur un écran tactile.</translation>
     </message>
     <message>
         <location line="+2"/>
@@ -1637,12 +1637,12 @@ Cela met l&apos;application en évidence dans la barre des tâches.</translation
     <message>
         <location line="+18"/>
         <source>Share keys with trusted users</source>
-        <translation type="unfinished"></translation>
+        <translation>Partager les clés avec les utilisateurs vérifiés</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Automatically replies to key requests from other users, if they are verified.</source>
-        <translation type="unfinished"></translation>
+        <translation>Automatiquement répondre aux demandes de clés de déchiffrement des autres utilisateurs, si ceux-ci sont vérifiés.</translation>
     </message>
     <message>
         <location line="+185"/>
@@ -1672,7 +1672,7 @@ Cela met l&apos;application en évidence dans la barre des tâches.</translation
     <message>
         <location line="-31"/>
         <source>Enter the passphrase to decrypt the file:</source>
-        <translation>Entrez la clé secrète pour déchiffrer le fichier&#xa0;&#xa0;:</translation>
+        <translation>Entrez la clé secrète pour déchiffrer le fichier  :</translation>
     </message>
     <message>
         <location line="+8"/>
@@ -1683,7 +1683,7 @@ Cela met l&apos;application en évidence dans la barre des tâches.</translation
     <message>
         <location line="-8"/>
         <source>Enter passphrase to encrypt your session keys:</source>
-        <translation>Entrez une clé secrète pour chiffrer vos clés de session&#xa0;&#xa0;:</translation>
+        <translation>Entrez une clé secrète pour chiffrer vos clés de session  :</translation>
     </message>
     <message>
         <location line="+15"/>
@@ -1696,27 +1696,27 @@ Cela met l&apos;application en évidence dans la barre des tâches.</translation
     <message>
         <location filename="../qml/device-verification/Waiting.qml" line="+7"/>
         <source>Waiting for other party</source>
-        <translation type="unfinished"></translation>
+        <translation>En attente du correspondant…</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Waiting for other side to accept the verification request.</source>
-        <translation type="unfinished"></translation>
+        <translation>Attente d&apos;acceptation de la demande de vérification par le correspondant…</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Waiting for other side to continue the verification request.</source>
-        <translation type="unfinished"></translation>
+        <translation>Attente de poursuite de la vérification par le correspondant…</translation>
     </message>
     <message>
         <location line="+2"/>
         <source>Waiting for other side to complete the verification request.</source>
-        <translation type="unfinished"></translation>
+        <translation>Attente de finalisation de la vérification par le correspondant…</translation>
     </message>
     <message>
         <location line="+15"/>
         <source>Cancel</source>
-        <translation type="unfinished">Annuler</translation>
+        <translation>Annuler</translation>
     </message>
 </context>
 <context>
@@ -2069,7 +2069,7 @@ attendant que la vérification des appareils soit opérationnelle.</translation>
     <message>
         <location line="+140"/>
         <source>Failed to enable encryption: %1</source>
-        <translation>Échec de l&apos;activation du chiffrement&#xa0;&#xa0;: %1</translation>
+        <translation>Échec de l&apos;activation du chiffrement  : %1</translation>
     </message>
     <message>
         <location line="+147"/>
@@ -2089,13 +2089,13 @@ attendant que la vérification des appareils soit opérationnelle.</translation>
     <message>
         <location line="+5"/>
         <source>Error while reading file: %1</source>
-        <translation>Erreur lors de la lecture du fichier&#xa0;&#xa0;: %1</translation>
+        <translation>Erreur lors de la lecture du fichier  : %1</translation>
     </message>
     <message>
         <location line="+35"/>
         <location line="+20"/>
         <source>Failed to upload image: %s</source>
-        <translation>Échec de l&apos;envoi de l&apos;image&#xa0;&#xa0;: %s</translation>
+        <translation>Échec de l&apos;envoi de l&apos;image  : %s</translation>
     </message>
 </context>
 <context>
@@ -2128,7 +2128,7 @@ attendant que la vérification des appareils soit opérationnelle.</translation>
     <message>
         <location line="+1"/>
         <source>Do you really want to invite %1 (%2) to a direct chat?</source>
-        <translation>Voulez-vous vraiment inviter %1 (%2) dans un chat privé&#x202f;&#x202f;?</translation>
+        <translation>Voulez-vous vraiment inviter %1 (%2) dans un chat privé  ?</translation>
     </message>
     <message>
         <location line="+54"/>
@@ -2244,12 +2244,12 @@ attendant que la vérification des appareils soit opérationnelle.</translation>
     <message>
         <location line="+5"/>
         <source>You: %1</source>
-        <translation>Vous&#xa0;&#xa0;: %1</translation>
+        <translation>Vous  : %1</translation>
     </message>
     <message>
         <location line="+3"/>
         <source>%1: %2</source>
-        <translation>%1&#xa0;&#xa0;: %2</translation>
+        <translation>%1  : %2</translation>
     </message>
     <message>
         <location line="+7"/>
diff --git a/resources/langs/nheko_ru.ts b/resources/langs/nheko_ru.ts
index bc3496469bd4c9b847c4e3208a2064152426d1b2..cbe3fe07179407e75ec35978b8ab73b5582caeb1 100644
--- a/resources/langs/nheko_ru.ts
+++ b/resources/langs/nheko_ru.ts
@@ -642,7 +642,7 @@ Example: https://server.my:8787</source>
     <message>
         <location filename="../qml/MessageInput.qml" line="+47"/>
         <source>Write a message...</source>
-        <translation type="unfinished">Написать сообщение...</translation>
+        <translation>Написать сообщение…</translation>
     </message>
 </context>
 <context>
@@ -719,7 +719,7 @@ Example: https://server.my:8787</source>
     <message>
         <location filename="../../src/QuickSwitcher.cpp" line="+74"/>
         <source>Search for a room...</source>
-        <translation>Поиск комнаты...</translation>
+        <translation>Поиск комнаты…</translation>
     </message>
 </context>
 <context>
@@ -951,7 +951,7 @@ Example: https://server.my:8787</source>
         <location line="+13"/>
         <location filename="../../src/TextInputWidget.h" line="+160"/>
         <source>Write a message...</source>
-        <translation>Написать сообщение...</translation>
+        <translation>Написать сообщение…</translation>
     </message>
     <message>
         <location line="+31"/>
@@ -986,7 +986,7 @@ Example: https://server.my:8787</source>
     <message>
         <location filename="../../src/TextInputWidget.h" line="-5"/>
         <source>Connection lost. Nheko is trying to re-connect...</source>
-        <translation>Соединение потеряно. Nheko пытается переподключиться...</translation>
+        <translation>Соединение потеряно. Nheko пытается переподключиться…</translation>
     </message>
 </context>
 <context>
diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml
index 181b9ba4c69c939ef73c44813edb0a16349b9816..2015517ca7fa0cf0a59889272558b7a0458b07cc 100644
--- a/resources/qml/TopBar.qml
+++ b/resources/qml/TopBar.qml
@@ -35,6 +35,8 @@ Rectangle {
             Layout.row: 0
             Layout.rowSpan: 2
             Layout.alignment: Qt.AlignVCenter
+            width: avatarSize
+            height: avatarSize
             visible: TimelineManager.isNarrowView
             image: ":/icons/icons/ui/angle-pointing-to-left.png"
             ToolTip.visible: hovered
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 993fbfe72c3254b780bd33dc23d9a1255fc6c9dd..b37f69b3e1ae3c159205c4079ee891147edd4d72 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1469,22 +1469,22 @@ Cache::getRoomInfo(const std::vector<std::string> &rooms)
         return room_info;
 }
 
-std::map<QString, mtx::responses::Timeline>
-Cache::roomMessages()
+std::vector<QString>
+Cache::roomIds()
 {
         auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
 
-        std::map<QString, mtx::responses::Timeline> msgs;
+        std::vector<QString> rooms;
         std::string room_id, unused;
 
         auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
         while (roomsCursor.get(room_id, unused, MDB_NEXT))
-                msgs.emplace(QString::fromStdString(room_id), mtx::responses::Timeline());
+                rooms.push_back(QString::fromStdString(room_id));
 
         roomsCursor.close();
         txn.commit();
 
-        return msgs;
+        return rooms;
 }
 
 QMap<QString, mtx::responses::Notifications>
@@ -3376,6 +3376,46 @@ Cache::markUserKeysOutOfDate(lmdb::txn &txn,
                                            });
 }
 
+void
+Cache::query_keys(const std::string &user_id,
+                  std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb)
+{
+        auto cache_ = cache::userKeys(user_id);
+
+        if (cache_.has_value()) {
+                if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) {
+                        cb(cache_.value(), {});
+                        return;
+                }
+        }
+
+        mtx::requests::QueryKeys req;
+        req.device_keys[user_id] = {};
+
+        std::string last_changed;
+        if (cache_)
+                last_changed = cache_->last_changed;
+        req.token = last_changed;
+
+        http::client()->query_keys(req,
+                                   [cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
+                                                               mtx::http::RequestErr err) {
+                                           if (err) {
+                                                   nhlog::net()->warn(
+                                                     "failed to query device keys: {},{}",
+                                                     err->matrix_error.errcode,
+                                                     static_cast<int>(err->status_code));
+                                                   cb({}, err);
+                                                   return;
+                                           }
+
+                                           cache::updateUserKeys(last_changed, res);
+
+                                           auto keys = cache::userKeys(user_id);
+                                           cb(keys.value_or(UserKeyCache{}), err);
+                                   });
+}
+
 void
 to_json(json &j, const VerificationCache &info)
 {
@@ -3927,10 +3967,10 @@ setCurrentFormat()
         instance_->setCurrentFormat();
 }
 
-std::map<QString, mtx::responses::Timeline>
-roomMessages()
+std::vector<QString>
+roomIds()
 {
-        return instance_->roomMessages();
+        return instance_->roomIds();
 }
 
 QMap<QString, mtx::responses::Notifications>
diff --git a/src/Cache.h b/src/Cache.h
index 98e6cb756cb3091c058259a403d531ab816d6fb9..4c4f707163ca46d31caae50650985119fa5b200b 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -28,11 +28,18 @@
 #include <lmdb++.h>
 #endif
 
-#include <mtx/responses.hpp>
+#include <mtx/events/event_type.hpp>
+#include <mtx/events/presence.hpp>
+#include <mtx/responses/crypto.hpp>
+#include <mtxclient/crypto/types.hpp>
 
 #include "CacheCryptoStructs.h"
 #include "CacheStructs.h"
 
+namespace mtx::responses {
+struct Notifications;
+}
+
 namespace cache {
 void
 init(const QString &user_id);
@@ -94,8 +101,6 @@ getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb);
 std::vector<RoomMember>
 getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30);
 
-void
-saveState(const mtx::responses::Sync &res);
 bool
 isInitialized();
 
@@ -128,9 +133,6 @@ setCurrentFormat();
 bool
 runMigrations();
 
-std::map<QString, mtx::responses::Timeline>
-roomMessages();
-
 QMap<QString, mtx::responses::Notifications>
 getTimelineMentions();
 
@@ -182,22 +184,8 @@ saveImage(const QString &url, const QByteArray &data);
 
 RoomInfo
 singleRoomInfo(const std::string &room_id);
-std::vector<std::string>
-roomsWithStateUpdates(const mtx::responses::Sync &res);
-std::vector<std::string>
-roomsWithTagUpdates(const mtx::responses::Sync &res);
 std::map<QString, RoomInfo>
 getRoomInfo(const std::vector<std::string> &rooms);
-inline std::map<QString, RoomInfo>
-roomUpdates(const mtx::responses::Sync &sync)
-{
-        return getRoomInfo(roomsWithStateUpdates(sync));
-}
-inline std::map<QString, RoomInfo>
-roomTagUpdates(const mtx::responses::Sync &sync)
-{
-        return getRoomInfo(roomsWithTagUpdates(sync));
-}
 
 //! Calculates which the read status of a room.
 //! Whether all the events in the timeline have been read.
diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h
index a693e2335a135fcd0807e56751e8a601987812d6..6256dcf9dcc1402c08fb8db7ec841c3c79d7d24e 100644
--- a/src/CacheCryptoStructs.h
+++ b/src/CacheCryptoStructs.h
@@ -3,10 +3,8 @@
 #include <map>
 #include <mutex>
 
-//#include <nlohmann/json.hpp>
-
-#include <mtx/responses.hpp>
-#include <mtxclient/crypto/client.hpp>
+#include <mtx/responses/crypto.hpp>
+#include <mtxclient/crypto/objects.hpp>
 
 // Extra information associated with an outbound megolm session.
 struct OutboundGroupSessionData
diff --git a/src/Cache_p.h b/src/Cache_p.h
index a32793ea7ca70b8ebe796b0d4e2e05ddbdf15997..05e13128c3311ebcc870503fdef34c8fd49bc1a7 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -33,8 +33,11 @@
 #endif
 #include <nlohmann/json.hpp>
 
-#include <mtx/responses.hpp>
+#include <mtx/responses/messages.hpp>
+#include <mtx/responses/notifications.hpp>
+#include <mtx/responses/sync.hpp>
 #include <mtxclient/crypto/client.hpp>
+#include <mtxclient/http/client.hpp>
 
 #include "CacheCryptoStructs.h"
 #include "CacheStructs.h"
@@ -65,6 +68,8 @@ public:
         void deleteUserKeys(lmdb::txn &txn,
                             lmdb::dbi &db,
                             const std::vector<std::string> &user_ids);
+        void query_keys(const std::string &user_id,
+                        std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb);
 
         // device & user verification cache
         VerificationStatus verificationStatus(const std::string &user_id);
@@ -113,8 +118,7 @@ public:
         void setCurrentFormat();
         bool runMigrations();
 
-        std::map<QString, mtx::responses::Timeline> roomMessages();
-
+        std::vector<QString> roomIds();
         QMap<QString, mtx::responses::Notifications> getTimelineMentions();
 
         //! Retrieve all the user ids from a room.
diff --git a/src/CallManager.cpp b/src/CallManager.cpp
index a376a607f6e999d9f70ea7378506c585a26050ae..ac0636e0073e814081930b6f48b54ac744cb983b 100644
--- a/src/CallManager.cpp
+++ b/src/CallManager.cpp
@@ -12,6 +12,7 @@
 #include "Logging.h"
 #include "MainWindow.h"
 #include "MatrixClient.h"
+#include "Utils.h"
 #include "WebRTCSession.h"
 #include "dialogs/AcceptCall.h"
 
@@ -29,8 +30,8 @@ std::vector<std::string>
 getTurnURIs(const mtx::responses::TurnServer &turnServer);
 }
 
-CallManager::CallManager()
-  : QObject()
+CallManager::CallManager(QObject *parent)
+  : QObject(parent)
   , session_(WebRTCSession::instance())
   , turnServerTimer_(this)
 {
diff --git a/src/CallManager.h b/src/CallManager.h
index f0e46b4b7d526c82b2ab88411464623027245546..da7569e2dff09adb97173b694e5a8f6865cb9e76 100644
--- a/src/CallManager.h
+++ b/src/CallManager.h
@@ -22,7 +22,7 @@ class CallManager : public QObject
         Q_OBJECT
 
 public:
-        CallManager();
+        CallManager(QObject *);
 
         void sendInvite(const QString &roomid, bool isVideo);
         void hangUp(
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 4d46b8c6d5bdd5ad593c7bd40955bbe8366fd19a..78987fb9515f17548adc0aa82c5c844d3629a33e 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -22,9 +22,12 @@
 #include <QShortcut>
 #include <QtConcurrent>
 
+#include <mtx/responses.hpp>
+
 #include "AvatarProvider.h"
 #include "Cache.h"
 #include "Cache_p.h"
+#include "CallManager.h"
 #include "ChatPage.h"
 #include "DeviceVerificationFlow.h"
 #include "EventAccessors.h"
@@ -69,6 +72,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
   , isConnected_(true)
   , userSettings_{userSettings}
   , notificationsManager(this)
+  , callManager_(new CallManager(this))
 {
         setObjectName("chatPage");
 
@@ -125,7 +129,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         contentLayout_->setSpacing(0);
         contentLayout_->setMargin(0);
 
-        view_manager_ = new TimelineViewManager(&callManager_, this);
+        view_manager_ = new TimelineViewManager(callManager_, this);
 
         contentLayout_->addWidget(view_manager_->getWidget());
 
@@ -433,8 +437,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                 });
 
         connect(text_input_, &TextInputWidget::callButtonPress, this, [this]() {
-                if (callManager_.onActiveCall()) {
-                        callManager_.hangUp();
+                if (callManager_->onActiveCall()) {
+                        callManager_->hangUp();
                 } else {
                         if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString());
                             roomInfo.member_count != 2) {
@@ -453,10 +457,10 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                                   userSettings_,
                                   MainWindow::instance());
                                 connect(dialog, &dialogs::PlaceCall::voice, this, [this]() {
-                                        callManager_.sendInvite(current_room_, false);
+                                        callManager_->sendInvite(current_room_, false);
                                 });
                                 connect(dialog, &dialogs::PlaceCall::video, this, [this]() {
-                                        callManager_.sendInvite(current_room_, true);
+                                        callManager_->sendInvite(current_room_, true);
                                 });
                                 utils::centerWidget(dialog, MainWindow::instance());
                                 dialog->show();
@@ -694,7 +698,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
                 const bool isInitialized = cache::isInitialized();
                 const auto cacheVersion  = cache::formatVersion();
 
-                callManager_.refreshTurnServer();
+                callManager_->refreshTurnServer();
 
                 if (!isInitialized) {
                         cache::setCurrentFormat();
@@ -764,7 +768,7 @@ ChatPage::loadStateFromCache()
                 cache::restoreSessions();
                 olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
 
-                emit initializeEmptyViews(cache::roomMessages());
+                emit initializeEmptyViews(cache::client()->roomIds());
                 emit initializeRoomList(cache::roomInfo());
                 emit initializeMentions(cache::getTimelineMentions());
                 emit syncTags(cache::roomInfo().toStdMap());
@@ -971,13 +975,64 @@ ChatPage::startInitialSync()
         opts.set_presence = currentPresence();
 
         http::client()->sync(
-          opts,
-          std::bind(
-            &ChatPage::initialSyncHandler, this, std::placeholders::_1, std::placeholders::_2));
+          opts, [this](const mtx::responses::Sync &res, mtx::http::RequestErr err) {
+                  // TODO: Initial Sync should include mentions as well...
+
+                  if (err) {
+                          const auto error      = QString::fromStdString(err->matrix_error.error);
+                          const auto msg        = tr("Please try to login again: %1").arg(error);
+                          const auto err_code   = mtx::errors::to_string(err->matrix_error.errcode);
+                          const int status_code = static_cast<int>(err->status_code);
+
+                          nhlog::net()->error("initial sync error: {} {}", status_code, err_code);
+
+                          // non http related errors
+                          if (status_code <= 0 || status_code >= 600) {
+                                  startInitialSync();
+                                  return;
+                          }
+
+                          switch (status_code) {
+                          case 502:
+                          case 504:
+                          case 524: {
+                                  startInitialSync();
+                                  return;
+                          }
+                          default: {
+                                  emit dropToLoginPageCb(msg);
+                                  return;
+                          }
+                          }
+                  }
+
+                  nhlog::net()->info("initial sync completed");
+
+                  try {
+                          cache::client()->saveState(res);
+
+                          olm::handle_to_device_messages(res.to_device.events);
+
+                          emit initializeViews(std::move(res.rooms));
+                          emit initializeRoomList(cache::roomInfo());
+                          emit initializeMentions(cache::getTimelineMentions());
+
+                          cache::calculateRoomReadStatus();
+                          emit syncTags(cache::roomInfo().toStdMap());
+                  } catch (const lmdb::error &e) {
+                          nhlog::db()->error("failed to save state after initial sync: {}",
+                                             e.what());
+                          startInitialSync();
+                          return;
+                  }
+
+                  emit trySyncCb();
+                  emit contentLoaded();
+          });
 }
 
 void
-ChatPage::handleSyncResponse(mtx::responses::Sync res)
+ChatPage::handleSyncResponse(const mtx::responses::Sync &res)
 {
         nhlog::net()->debug("sync completed: {}", res.next_batch);
 
@@ -986,16 +1041,16 @@ ChatPage::handleSyncResponse(mtx::responses::Sync res)
 
         // TODO: fine grained error handling
         try {
-                cache::saveState(res);
+                cache::client()->saveState(res);
                 olm::handle_to_device_messages(res.to_device.events);
 
-                auto updates = cache::roomUpdates(res);
+                auto updates = cache::getRoomInfo(cache::client()->roomsWithStateUpdates(res));
 
                 emit syncRoomlist(updates);
 
                 emit syncUI(res.rooms);
 
-                emit syncTags(cache::roomTagUpdates(res));
+                emit syncTags(cache::getRoomInfo(cache::client()->roomsWithTagUpdates(res)));
 
                 // if we process a lot of syncs (1 every 200ms), this means we clean the
                 // db every 100s
@@ -1070,7 +1125,7 @@ ChatPage::joinRoom(const QString &room)
         const auto room_id = room.toStdString();
 
         http::client()->join_room(
-          room_id, [this, room_id](const nlohmann::json &, mtx::http::RequestErr err) {
+          room_id, [this, room_id](const mtx::responses::RoomId &, mtx::http::RequestErr err) {
                   if (err) {
                           emit showNotification(
                             tr("Failed to join room: %1")
@@ -1116,7 +1171,8 @@ void
 ChatPage::leaveRoom(const QString &room_id)
 {
         http::client()->leave_room(
-          room_id.toStdString(), [this, room_id](const json &, mtx::http::RequestErr err) {
+          room_id.toStdString(),
+          [this, room_id](const mtx::responses::Empty &, mtx::http::RequestErr err) {
                   if (err) {
                           emit showNotification(
                             tr("Failed to leave room: %1")
@@ -1291,62 +1347,6 @@ ChatPage::currentPresence() const
         }
 }
 
-void
-ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
-{
-        // TODO: Initial Sync should include mentions as well...
-
-        if (err) {
-                const auto error      = QString::fromStdString(err->matrix_error.error);
-                const auto msg        = tr("Please try to login again: %1").arg(error);
-                const auto err_code   = mtx::errors::to_string(err->matrix_error.errcode);
-                const int status_code = static_cast<int>(err->status_code);
-
-                nhlog::net()->error("initial sync error: {} {}", status_code, err_code);
-
-                // non http related errors
-                if (status_code <= 0 || status_code >= 600) {
-                        startInitialSync();
-                        return;
-                }
-
-                switch (status_code) {
-                case 502:
-                case 504:
-                case 524: {
-                        startInitialSync();
-                        return;
-                }
-                default: {
-                        emit dropToLoginPageCb(msg);
-                        return;
-                }
-                }
-        }
-
-        nhlog::net()->info("initial sync completed");
-
-        try {
-                cache::saveState(res);
-
-                olm::handle_to_device_messages(res.to_device.events);
-
-                emit initializeViews(std::move(res.rooms));
-                emit initializeRoomList(cache::roomInfo());
-                emit initializeMentions(cache::getTimelineMentions());
-
-                cache::calculateRoomReadStatus();
-                emit syncTags(cache::roomInfo().toStdMap());
-        } catch (const lmdb::error &e) {
-                nhlog::db()->error("failed to save state after initial sync: {}", e.what());
-                startInitialSync();
-                return;
-        }
-
-        emit trySyncCb();
-        emit contentLoaded();
-}
-
 void
 ChatPage::ensureOneTimeKeyCount(const std::map<std::string, uint16_t> &counts)
 {
@@ -1455,51 +1455,11 @@ ChatPage::initiateLogout()
         emit showOverlayProgressBar();
 }
 
-void
-ChatPage::query_keys(const std::string &user_id,
-                     std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb)
-{
-        auto cache_ = cache::userKeys(user_id);
-
-        if (cache_.has_value()) {
-                if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) {
-                        cb(cache_.value(), {});
-                        return;
-                }
-        }
-
-        mtx::requests::QueryKeys req;
-        req.device_keys[user_id] = {};
-
-        std::string last_changed;
-        if (cache_)
-                last_changed = cache_->last_changed;
-        req.token = last_changed;
-
-        http::client()->query_keys(req,
-                                   [cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
-                                                               mtx::http::RequestErr err) {
-                                           if (err) {
-                                                   nhlog::net()->warn(
-                                                     "failed to query device keys: {},{}",
-                                                     err->matrix_error.errcode,
-                                                     static_cast<int>(err->status_code));
-                                                   cb({}, err);
-                                                   return;
-                                           }
-
-                                           cache::updateUserKeys(last_changed, res);
-
-                                           auto keys = cache::userKeys(user_id);
-                                           cb(keys.value_or(UserKeyCache{}), err);
-                                   });
-}
-
 template<typename T>
 void
 ChatPage::connectCallMessage()
 {
-        connect(&callManager_,
+        connect(callManager_,
                 qOverload<const QString &, const T &>(&CallManager::newMessage),
                 view_manager_,
                 qOverload<const QString &, const T &>(&TimelineViewManager::queueCallMessage));
diff --git a/src/ChatPage.h b/src/ChatPage.h
index a29cea7bd7ab960800f5f55a246a106483b12bd1..0c12d89fa2acd21a6934c4a658f11a2d3f231c03 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -23,9 +23,10 @@
 #include <variant>
 
 #include <mtx/common.hpp>
-#include <mtx/requests.hpp>
-#include <mtx/responses.hpp>
-#include <mtxclient/http/errors.hpp>
+#include <mtx/events.hpp>
+#include <mtx/events/encrypted.hpp>
+#include <mtx/events/member.hpp>
+#include <mtx/events/presence.hpp>
 
 #include <QFrame>
 #include <QHBoxLayout>
@@ -37,11 +38,8 @@
 
 #include "CacheCryptoStructs.h"
 #include "CacheStructs.h"
-#include "CallManager.h"
 #include "CommunitiesList.h"
-#include "Utils.h"
 #include "notifications/Manager.h"
-#include "popups/UserMentions.h"
 
 class OverlayModal;
 class QuickSwitcher;
@@ -54,13 +52,25 @@ class UserInfoWidget;
 class UserSettings;
 class NotificationsManager;
 class TimelineModel;
+class CallManager;
 
 constexpr int CONSENSUS_TIMEOUT      = 1000;
 constexpr int SHOW_CONTENT_TIMEOUT   = 3000;
 constexpr int TYPING_REFRESH_TIMEOUT = 10000;
 
-namespace mtx::http {
-using RequestErr = const std::optional<mtx::http::ClientError> &;
+namespace mtx::requests {
+struct CreateRoom;
+}
+namespace mtx::responses {
+struct Notifications;
+struct Sync;
+struct Timeline;
+struct Rooms;
+struct LeftRoom;
+}
+
+namespace popups {
+class UserMentions;
 }
 
 class ChatPage : public QWidget
@@ -89,8 +99,6 @@ public:
         //! Show the room/group list (if it was visible).
         void showSideBars();
         void initiateLogout();
-        void query_keys(const std::string &req,
-                        std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb);
         void focusMessageInput();
 
         QString status() const;
@@ -145,12 +153,12 @@ signals:
         void trySyncCb();
         void tryDelayedSyncCb();
         void tryInitialSyncCb();
-        void newSyncResponse(mtx::responses::Sync res);
+        void newSyncResponse(const mtx::responses::Sync &res);
         void leftRoom(const QString &room_id);
 
         void initializeRoomList(QMap<QString, RoomInfo>);
         void initializeViews(const mtx::responses::Rooms &rooms);
-        void initializeEmptyViews(const std::map<QString, mtx::responses::Timeline> &msgs);
+        void initializeEmptyViews(const std::vector<QString> &roomIds);
         void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs);
         void syncUI(const mtx::responses::Rooms &rooms);
         void syncRoomlist(const std::map<QString, RoomInfo> &updates);
@@ -194,14 +202,11 @@ private slots:
 
         void joinRoom(const QString &room);
         void sendTypingNotifications();
-        void handleSyncResponse(mtx::responses::Sync res);
+        void handleSyncResponse(const mtx::responses::Sync &res);
 
 private:
         static ChatPage *instance_;
 
-        //! Handler callback for initial sync. It doesn't run on the main thread so all
-        //! communication with the GUI should be done through signals.
-        void initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err);
         void startInitialSync();
         void tryInitialSync();
         void trySync();
@@ -276,7 +281,7 @@ private:
         QSharedPointer<UserSettings> userSettings_;
 
         NotificationsManager notificationsManager;
-        CallManager callManager_;
+        CallManager *callManager_;
 };
 
 template<class Collection>
diff --git a/src/CommunitiesList.cpp b/src/CommunitiesList.cpp
index 8a9386461cf2b6c4c35ac34e4400b3d0558e87bb..c1d0706f2c6787d0d53a003c730f55fe63bd7998 100644
--- a/src/CommunitiesList.cpp
+++ b/src/CommunitiesList.cpp
@@ -5,6 +5,7 @@
 #include "Splitter.h"
 
 #include <mtx/responses/groups.hpp>
+#include <nlohmann/json.hpp>
 
 #include <QLabel>
 
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index aa1a960703a35778d1284454fca5bf9534f461f6..509fce8cbf29484829d4d8d3ac10703be64fdcdf 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -1,8 +1,10 @@
 #include "DeviceVerificationFlow.h"
 
 #include "Cache.h"
+#include "Cache_p.h"
 #include "ChatPage.h"
 #include "Logging.h"
+#include "Utils.h"
 #include "timeline/TimelineModel.h"
 
 #include <QDateTime>
@@ -39,7 +41,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
 
         auto user_id   = userID.toStdString();
         this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(user_id);
-        ChatPage::instance()->query_keys(
+        cache::client()->query_keys(
           user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
                   if (err) {
                           nhlog::net()->warn("failed to query device keys: {},{}",
@@ -57,7 +59,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
                   this->their_keys = res;
           });
 
-        ChatPage::instance()->query_keys(
+        cache::client()->query_keys(
           http::client()->user_id().to_string(),
           [this](const UserKeyCache &res, mtx::http::RequestErr err) {
                   if (err) {
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index 70b5d9b3845b1473b02a3de197d093c6bd3f5938..d6e5411e92ddb675386c7f27f41d281cb0b9f9c2 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -3,6 +3,7 @@
 #include <QObject>
 
 #include <mtx/responses/crypto.hpp>
+#include <nlohmann/json.hpp>
 
 #include "CacheCryptoStructs.h"
 #include "Logging.h"
diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index b62be9a5f908551df67604f0cf86543c8e9b5e7e..3ae781f048f730cb60539cb79f9968c890327f76 100644
--- a/src/EventAccessors.cpp
+++ b/src/EventAccessors.cpp
@@ -1,5 +1,7 @@
 #include "EventAccessors.h"
 
+#include <nlohmann/json.hpp>
+
 #include <algorithm>
 #include <cctype>
 #include <type_traits>
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index f7c9fbf0d2d141019e8066b0ca7053b5d4bb787b..37b541518f89bd4fed360f7eac3fabf31a3c2951 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -23,6 +23,7 @@
 #include <QShortcut>
 
 #include <mtx/requests.hpp>
+#include <mtx/responses/login.hpp>
 
 #include "Cache.h"
 #include "ChatPage.h"
diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp
index b59fdff8a96c2bcd6485505afb33c8357fc77901..d656427794e07bd65116d8e82131910f42b62aa4 100644
--- a/src/MxcImageProvider.cpp
+++ b/src/MxcImageProvider.cpp
@@ -1,5 +1,7 @@
 #include "MxcImageProvider.h"
 
+#include <mtxclient/crypto/client.hpp>
+
 #include "Cache.h"
 #include "Logging.h"
 #include "MatrixClient.h"
diff --git a/src/Olm.cpp b/src/Olm.cpp
index 6e68bd425a226c00c31fd5182208ab2b08ed2cd6..af8bb512e6a5101fd69d8776f166c19880fea39d 100644
--- a/src/Olm.cpp
+++ b/src/Olm.cpp
@@ -1,6 +1,7 @@
 #include "Olm.h"
 
 #include <QObject>
+#include <nlohmann/json.hpp>
 #include <variant>
 
 #include "Cache.h"
@@ -20,6 +21,21 @@ auto client_ = std::make_unique<mtx::crypto::OlmClient>();
 }
 
 namespace olm {
+void
+from_json(const nlohmann::json &obj, OlmMessage &msg)
+{
+        if (obj.at("type") != "m.room.encrypted")
+                throw std::invalid_argument("invalid type for olm message");
+
+        if (obj.at("content").at("algorithm") != OLM_ALGO)
+                throw std::invalid_argument("invalid algorithm for olm message");
+
+        msg.sender     = obj.at("sender");
+        msg.sender_key = obj.at("content").at("sender_key");
+        msg.ciphertext = obj.at("content")
+                           .at("ciphertext")
+                           .get<std::map<std::string, mtx::events::msg::OlmCipherContent>>();
+}
 
 mtx::crypto::OlmClient *
 client()
@@ -419,8 +435,8 @@ send_key_request_for(mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> e,
                                e.content.session_id);
 
         mtx::events::msg::KeyRequest request;
-        request.action = !cancel ? mtx::events::msg::RequestAction::Request
-                                 : mtx::events::msg::RequestAction::Cancellation;
+        request.action               = !cancel ? mtx::events::msg::RequestAction::Request
+                                               : mtx::events::msg::RequestAction::Cancellation;
         request.algorithm            = MEGOLM_ALGO;
         request.room_id              = e.room_id;
         request.sender_key           = e.content.sender_key;
diff --git a/src/Olm.h b/src/Olm.h
index 322affa1843443b10867b827aa0aea521365e421..3400f993032c9628f7a565cdbba87eda4d5b85a1 100644
--- a/src/Olm.h
+++ b/src/Olm.h
@@ -40,21 +40,8 @@ struct OlmMessage
         std::map<RecipientKey, mtx::events::msg::OlmCipherContent> ciphertext;
 };
 
-inline void
-from_json(const nlohmann::json &obj, OlmMessage &msg)
-{
-        if (obj.at("type") != "m.room.encrypted")
-                throw std::invalid_argument("invalid type for olm message");
-
-        if (obj.at("content").at("algorithm") != OLM_ALGO)
-                throw std::invalid_argument("invalid algorithm for olm message");
-
-        msg.sender     = obj.at("sender");
-        msg.sender_key = obj.at("content").at("sender_key");
-        msg.ciphertext = obj.at("content")
-                           .at("ciphertext")
-                           .get<std::map<std::string, mtx::events::msg::OlmCipherContent>>();
-}
+void
+from_json(const nlohmann::json &obj, OlmMessage &msg);
 
 mtx::crypto::OlmClient *
 client();
diff --git a/src/RoomInfoListItem.h b/src/RoomInfoListItem.h
index da5a1bc4b8e0404669fa6cbcb0ae957e839c95c9..af919592673b465cb770c867cdbc76beb21b787b 100644
--- a/src/RoomInfoListItem.h
+++ b/src/RoomInfoListItem.h
@@ -22,7 +22,7 @@
 #include <QSharedPointer>
 #include <QWidget>
 
-#include <mtx/responses.hpp>
+#include <mtx/responses/sync.hpp>
 
 #include "CacheStructs.h"
 #include "UserSettingsPage.h"
diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp
index e6a10f0a4ed3f041aba7fa812eec4cbe0660f712..13a7c6d0074f3655b6d93fe0be2a20e11ff8f10b 100644
--- a/src/TextInputWidget.cpp
+++ b/src/TextInputWidget.cpp
@@ -453,8 +453,8 @@ FilteredTextEdit::completerRect()
         auto item_height = completer_->popup()->sizeHintForRow(0);
         auto max_height  = item_height * completer_->maxVisibleItems();
         auto height      = (completer_->completionCount() > completer_->maxVisibleItems())
-                        ? max_height
-                        : completer_->completionCount() * item_height;
+                             ? max_height
+                             : completer_->completionCount() * item_height;
         rect.setWidth(completer_->popup()->sizeHintForColumn(0));
         rect.moveBottom(-height);
         return rect;
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 308ec9a2c3f347bd60ec6198d6fd61d4b57070cf..a5a40111ba525f3723d235a1f96e3ad47aa032cf 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -1006,11 +1006,7 @@ UserSettingsPage::importSessionKeys()
                 auto sessions =
                   mtx::crypto::decrypt_exported_sessions(payload, password.toStdString());
                 cache::importSessionKeys(std::move(sessions));
-        } catch (const mtx::crypto::sodium_exception &e) {
-                QMessageBox::warning(this, tr("Error"), e.what());
-        } catch (const lmdb::error &e) {
-                QMessageBox::warning(this, tr("Error"), e.what());
-        } catch (const nlohmann::json::exception &e) {
+        } catch (const std::exception &e) {
                 QMessageBox::warning(this, tr("Error"), e.what());
         }
 }
@@ -1058,11 +1054,7 @@ UserSettingsPage::exportSessionKeys()
                 QTextStream out(&file);
                 out << prefix << newline << b64 << newline << suffix;
                 file.close();
-        } catch (const mtx::crypto::sodium_exception &e) {
-                QMessageBox::warning(this, tr("Error"), e.what());
-        } catch (const lmdb::error &e) {
-                QMessageBox::warning(this, tr("Error"), e.what());
-        } catch (const nlohmann::json::exception &e) {
+        } catch (const std::exception &e) {
                 QMessageBox::warning(this, tr("Error"), e.what());
         }
 }
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 0bfc82c39b803e878448404a82c2c73daadb0d8b..38dbba220bfcf742baddf7337ac76726855ad312 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -638,7 +638,7 @@ utils::luminance(const QColor &col)
         qreal lumRgb[3];
 
         for (int i = 0; i < 3; i++) {
-                qreal v                  = colRgb[i] / 255.0;
+                qreal v = colRgb[i] / 255.0;
                 v <= 0.03928 ? lumRgb[i] = v / 12.92 : lumRgb[i] = qPow((v + 0.055) / 1.055, 2.4);
         }
 
diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp
index 822b72189c0604ed07bbbf5d3c35a8380f3d295b..5b7dc59a208ce8be42c6501e6fc73c3f0498af0c 100644
--- a/src/dialogs/RoomSettings.cpp
+++ b/src/dialogs/RoomSettings.cpp
@@ -17,6 +17,8 @@
 #include <QVBoxLayout>
 
 #include "dialogs/RoomSettings.h"
+#include <mtx/responses/common.hpp>
+#include <mtx/responses/media.hpp>
 
 #include "Cache.h"
 #include "ChatPage.h"
diff --git a/src/popups/SuggestionsPopup.cpp b/src/popups/SuggestionsPopup.cpp
index 8f355b3836a4682887808071068dd92f6cbdf3e8..e84435b77f72904746080cf162761590fa4934c7 100644
--- a/src/popups/SuggestionsPopup.cpp
+++ b/src/popups/SuggestionsPopup.cpp
@@ -19,6 +19,12 @@ SuggestionsPopup::SuggestionsPopup(QWidget *parent)
         layout_->setSpacing(0);
 }
 
+QString
+SuggestionsPopup::displayName(QString room, QString user)
+{
+        return cache::displayName(room, user);
+}
+
 void
 SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
 {
diff --git a/src/popups/SuggestionsPopup.h b/src/popups/SuggestionsPopup.h
index 73bfe6f7ae9f716d316e99f91f0bfa7c3d0ad81f..c66f29033fc7d337f9f2dccaa1459fa174bbd018 100644
--- a/src/popups/SuggestionsPopup.h
+++ b/src/popups/SuggestionsPopup.h
@@ -22,7 +22,7 @@ public:
 
                 const auto &widget = qobject_cast<Item *>(item->widget());
                 emit itemSelected(
-                  cache::displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
+                  displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
 
                 resetSelection();
         }
@@ -47,6 +47,7 @@ signals:
         void itemSelected(const QString &user);
 
 private:
+        QString displayName(QString roomid, QString userid);
         void hoverSelection();
         void resetSelection() { selectedItem_ = -1; }
         void selectFirstItem() { selectedItem_ = 0; }
diff --git a/src/popups/UserMentions.h b/src/popups/UserMentions.h
index b7c4e51d4ffb0db34e51155c30850da296f37a6b..885fe67dd83eb43deaeaff1a85aab614fcf5c042 100644
--- a/src/popups/UserMentions.h
+++ b/src/popups/UserMentions.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <mtx/responses.hpp>
+#include <mtx/responses/notifications.hpp>
 
 #include <QMap>
 #include <QString>
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 38292f49e8b43ebb57486e383146129cd1c15242..1cb729d3e6a3e04ece2646c3afb9bf4f0a5e339a 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -3,6 +3,8 @@
 #include <QThread>
 #include <QTimer>
 
+#include <mtx/responses/common.hpp>
+
 #include "Cache.h"
 #include "Cache_p.h"
 #include "ChatPage.h"
@@ -10,6 +12,7 @@
 #include "Logging.h"
 #include "MatrixClient.h"
 #include "Olm.h"
+#include "Utils.h"
 
 Q_DECLARE_METATYPE(Reaction)
 
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 598af31ecb6548fe34a298cb843fa0e35bf2c95f..f9d7d00c5a39f9350ea663426ca0d79fc20d4044 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -11,6 +11,7 @@
 #include "ChatPage.h"
 #include "ColorImageProvider.h"
 #include "DelegateChooser.h"
+#include "DeviceVerificationFlow.h"
 #include "Logging.h"
 #include "MainWindow.h"
 #include "MatrixClient.h"
@@ -461,13 +462,10 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s
 }
 
 void
-TimelineViewManager::initWithMessages(const std::map<QString, mtx::responses::Timeline> &msgs)
+TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
 {
-        for (const auto &e : msgs) {
-                addRoom(e.first);
-
-                models.value(e.first)->addEvents(e.second);
-        }
+        for (const auto &roomId : roomIds)
+                addRoom(roomId);
 }
 
 void
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 895c4b399ef098b0bcce7a59242dcd1b533521f9..67eeee5bf13ff99b8cadb754ed36affaaaf41476 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -7,11 +7,11 @@
 #include <QWidget>
 
 #include <mtx/common.hpp>
-#include <mtx/responses.hpp>
+#include <mtx/responses/messages.hpp>
+#include <mtx/responses/sync.hpp>
 
 #include "Cache.h"
 #include "CallManager.h"
-#include "DeviceVerificationFlow.h"
 #include "Logging.h"
 #include "TimelineModel.h"
 #include "Utils.h"
@@ -24,6 +24,7 @@ class BlurhashProvider;
 class ColorImageProvider;
 class UserSettings;
 class ChatPage;
+class DeviceVerificationFlow;
 
 class TimelineViewManager : public QObject
 {
@@ -97,7 +98,7 @@ signals:
 public slots:
         void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
         void receivedSessionKey(const std::string &room_id, const std::string &session_id);
-        void initWithMessages(const std::map<QString, mtx::responses::Timeline> &msgs);
+        void initWithMessages(const std::vector<QString> &roomIds);
 
         void setHistoryView(const QString &room_id);
         void updateColorPalette();
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 2bb0370f35c8e79284ae1e9a02f434258e8df5ac..974aa5cc74bd4d3145a9b20f628146bd1c65ff67 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -117,7 +117,7 @@ UserProfile::fetchDeviceList(const QString &userID)
 {
         auto localUser = utils::localUser();
 
-        ChatPage::instance()->query_keys(
+        cache::client()->query_keys(
           userID.toStdString(),
           [other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
                                                        mtx::http::RequestErr err) {
@@ -129,7 +129,7 @@ UserProfile::fetchDeviceList(const QString &userID)
                   }
 
                   // Finding if the User is Verified or not based on the Signatures
-                  ChatPage::instance()->query_keys(
+                  cache::client()->query_keys(
                     utils::localUser().toStdString(),
                     [other_user_id, other_user_keys, this](const UserKeyCache &res,
                                                            mtx::http::RequestErr err) {
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 77b223237d1494c94856f5835d27b56b0a033804..62151266af45855c1eca2b04fd0b3a1cde46ddc4 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -5,8 +5,6 @@
 #include <QString>
 #include <QVector>
 
-#include "MatrixClient.h"
-
 namespace verification {
 Q_NAMESPACE
 
@@ -116,8 +114,4 @@ private:
         bool isUserVerified = false;
         TimelineViewManager *manager;
         TimelineModel *model;
-
-        void callback_fn(const mtx::responses::QueryKeys &res,
-                         mtx::http::RequestErr err,
-                         std::string user_id);
 };