diff --git a/CHANGES.md b/CHANGES.md
index 3824fead36..7021877ced 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,70 @@
+Changes in Element v1.3.8 (2021-11-17)
+======================================
+
+Features ✨
+----------
+ - Make notification text spoiler aware ([#3477](https://github.com/vector-im/element-android/issues/3477))
+ - Poll Feature - Create Poll Screen (Disabled for now) ([#4367](https://github.com/vector-im/element-android/issues/4367))
+ - Adds support for images inside message notifications ([#4402](https://github.com/vector-im/element-android/issues/4402))
+
+Bugfixes 🐛
+----------
+ - Render markdown in room list ([#452](https://github.com/vector-im/element-android/issues/452))
+ - Fix incorrect cropping of conversation icons ([#4424](https://github.com/vector-im/element-android/issues/4424))
+ - Fix potential NullPointerException crashes in Room and User account data sources ([#4428](https://github.com/vector-im/element-android/issues/4428))
+ - Unable to establish Olm outbound session from fallback key ([#4446](https://github.com/vector-im/element-android/issues/4446))
+ - Fixes intermittent crash on sign out due to the session being incorrectly recreated whilst being closed ([#4480](https://github.com/vector-im/element-android/issues/4480))
+
+SDK API changes ⚠️
+------------------
+ - Add content scanner API from MSC1453
+  API documentation : https://github.com/matrix-org/matrix-content-scanner#api ([#4392](https://github.com/vector-im/element-android/issues/4392))
+ - Breaking SDK API change to PushRuleListener, the separated callbacks have been merged into one with a data class which includes all the previously separated push information ([#4401](https://github.com/vector-im/element-android/issues/4401))
+
+Other changes
+-------------
+ - Finish migration from RxJava to Flow ([#4219](https://github.com/vector-im/element-android/issues/4219))
+ - Remove redundant text in feature request issue form ([#4257](https://github.com/vector-im/element-android/issues/4257))
+ - Add and improve issue triage workflows ([#4435](https://github.com/vector-im/element-android/issues/4435))
+ - Update issue template to bring in line with element-web ([#4452](https://github.com/vector-im/element-android/issues/4452))
+
+
+Changes in Element v1.3.7 (2021-11-04)
+======================================
+
+Features ✨
+----------
+ - Adding the room name to the invitation notification (if the room summary is available) ([#582](https://github.com/vector-im/element-android/issues/582))
+ - Updating single sign on providers ordering to match priority/popularity ([#4277](https://github.com/vector-im/element-android/issues/4277))
+
+Bugfixes 🐛
+----------
+ - Stops showing a dedicated redacted event notification, the message notifications will update accordingly ([#1491](https://github.com/vector-im/element-android/issues/1491))
+ - Fixes marking individual notifications as read causing other notifications to be dismissed ([#3395](https://github.com/vector-im/element-android/issues/3395))
+ - Fixing missing send button in light mode dev tools - send * event ([#3674](https://github.com/vector-im/element-android/issues/3674))
+ - Fixing room search needing exact casing for non latin-1 character named rooms ([#3968](https://github.com/vector-im/element-android/issues/3968))
+ - Fixing call ringtones only playing once when the ringtone doesn't contain looping metadata (android 9.0 and above) ([#4047](https://github.com/vector-im/element-android/issues/4047))
+ - Tentatively fixing the doubled notifications by updating the group summary at specific points in the notification rendering cycle ([#4152](https://github.com/vector-im/element-android/issues/4152))
+ - Do not show shortcuts if a PIN code is set ([#4170](https://github.com/vector-im/element-android/issues/4170))
+ - Fixes being unable to join rooms by name ([#4255](https://github.com/vector-im/element-android/issues/4255))
+ - Fixing missing F-Droid notifications when in background due to background syncs not triggering ([#4298](https://github.com/vector-im/element-android/issues/4298))
+ - Fix video compression before upload ([#4353](https://github.com/vector-im/element-android/issues/4353))
+ - Fixing QR code crashes caused by a known issue in the zxing library for older versions of android by downgrading to 3.3.3 ([#4361](https://github.com/vector-im/element-android/issues/4361))
+ - Fixing timeline crash when rotating with the emoji window open ([#4365](https://github.com/vector-im/element-android/issues/4365))
+ - Fix handling of links coming from web instance reported as malformed by mistake ([#4369](https://github.com/vector-im/element-android/issues/4369))
+
+SDK API changes ⚠️
+------------------
+ - Add API `LoginWizard.loginCustom(data: JsonDict): Session` to be able to login to a homeserver using arbitrary request content ([#4266](https://github.com/vector-im/element-android/issues/4266))
+ - Add optional deviceId to the login API ([#4334](https://github.com/vector-im/element-android/issues/4334))
+
+Other changes
+-------------
+ - Migrate app DI framework to Hilt ([#3888](https://github.com/vector-im/element-android/issues/3888))
+ - Limit supported TLS versions and cipher suites ([#4192](https://github.com/vector-im/element-android/issues/4192))
+ - Fixed capitalisation of text on initial sync screen ([#4292](https://github.com/vector-im/element-android/issues/4292))
+
+
 Changes in Element v1.3.6 (2021-10-26)
 ======================================
 
diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
index 4ca6ced8fe..573138bf5c 100644
--- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
+++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt
@@ -17,6 +17,7 @@
 
 package im.vector.lib.attachmentviewer
 
+import android.annotation.SuppressLint
 import android.graphics.Color
 import android.os.Build
 import android.os.Bundle
@@ -141,7 +142,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
             // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
             window.setDecorFitsSystemWindows(false)
             // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
-            window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+            } else {
+                @SuppressLint("WrongConstant")
+                window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
+            }
             // New API instead of FLAG_TRANSLUCENT_STATUS
             window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
             // new API instead of FLAG_TRANSLUCENT_NAVIGATION
@@ -347,7 +353,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
             // new API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION
             window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars())
             // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
-            window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+            } else {
+                @SuppressLint("WrongConstant")
+                window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
+            }
             // New API instead of FLAG_TRANSLUCENT_STATUS
             window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar)
             // New API instead of FLAG_TRANSLUCENT_NAVIGATION
diff --git a/build.gradle b/build.gradle
index 77ac352d85..6c6aab57f5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,6 +17,7 @@ buildscript {
         // https://developer.android.com/studio/releases/gradle-plugin
         classpath libs.gradle.gradlePlugin
         classpath libs.gradle.kotlinPlugin
+        classpath libs.gradle.hiltPlugin
         classpath 'com.google.gms:google-services:4.3.10'
         classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3'
         classpath 'com.google.android.gms:oss-licenses-plugin:0.10.4'
diff --git a/dependencies.gradle b/dependencies.gradle
index 9b11d397af..bf8b6aaeb1 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -1,8 +1,8 @@
 ext.versions = [
 
         'minSdk'            : 21,
-        'compileSdk'        : 30,
-        'targetSdk'         : 30,
+        'compileSdk'        : 31,
+        'targetSdk'         : 31,
         'sourceCompat'      : JavaVersion.VERSION_1_8,
         'targetCompat'      : JavaVersion.VERSION_1_8,
 ]
@@ -11,13 +11,13 @@ def gradle = "7.0.3"
 // Ref: https://kotlinlang.org/releases.html
 def kotlin = "1.5.31"
 def kotlinCoroutines = "1.5.2"
-def dagger = "2.39.1"
+def dagger = "2.40.1"
 def retrofit = "2.9.0"
 def arrow = "0.8.2"
 def markwon = "4.6.2"
 def moshi = "1.12.0"
-def lifecycle = "2.2.0"
-def rxBinding = "3.1.0"
+def lifecycle = "2.4.0"
+def flowBinding = "1.2.0"
 def epoxy = "4.6.2"
 def mavericks = "2.4.0"
 def glide = "4.12.0"
@@ -26,7 +26,7 @@ def jjwt = "0.11.2"
 def vanniktechEmoji = "0.8.0"
 
 // Testing
-def mockk = "1.12.0"
+def mockk = "1.12.1"
 def espresso = "3.4.0"
 def androidxTest = "1.4.0"
 
@@ -34,28 +34,31 @@ def androidxTest = "1.4.0"
 ext.libs = [
         gradle      : [
                 'gradlePlugin'            : "com.android.tools.build:gradle:$gradle",
-                'kotlinPlugin'            : "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
+                'kotlinPlugin'            : "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin",
+                'hiltPlugin'              : "com.google.dagger:hilt-android-gradle-plugin:$dagger"
+
         ],
         jetbrains   : [
                 'kotlinReflect'           : "org.jetbrains.kotlin:kotlin-reflect:$kotlin",
                 'coroutinesCore'          : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines",
                 'coroutinesAndroid'       : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines",
-                'coroutinesRx2'           : "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutines"
+                'coroutinesRx2'           : "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutines",
+                'coroutinesTest'          : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
         ],
         androidx    : [
                 'appCompat'               : "androidx.appcompat:appcompat:1.3.1",
-                'core'                    : "androidx.core:core-ktx:1.6.0",
+                'core'                    : "androidx.core:core-ktx:1.7.0",
                 'recyclerview'            : "androidx.recyclerview:recyclerview:1.2.1",
                 'exifinterface'           : "androidx.exifinterface:exifinterface:1.3.3",
                 'fragmentKtx'             : "androidx.fragment:fragment-ktx:1.3.6",
                 'constraintLayout'        : "androidx.constraintlayout:constraintlayout:2.1.1",
-                'work'                    : "androidx.work:work-runtime-ktx:2.6.0",
+                'work'                    : "androidx.work:work-runtime-ktx:2.7.0",
                 'autoFill'                : "androidx.autofill:autofill:1.1.0",
                 'preferenceKtx'           : "androidx.preference:preference-ktx:1.1.1",
                 'junit'                   : "androidx.test.ext:junit:1.1.3",
-                'lifecycleExtensions'     : "androidx.lifecycle:lifecycle-extensions:$lifecycle",
-                'lifecycleJava8'          : "androidx.lifecycle:lifecycle-common-java8:$lifecycle",
-                'lifecycleLivedata'       : "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1",
+                'lifecycleCommon'         : "androidx.lifecycle:lifecycle-common:$lifecycle",
+                'lifecycleLivedata'       : "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle",
+                'lifecycleProcess'        : "androidx.lifecycle:lifecycle-process:$lifecycle",
                 'datastore'               : "androidx.datastore:datastore:1.0.0",
                 'datastorepreferences'    : "androidx.datastore:datastore-preferences:1.0.0",
                 'pagingRuntimeKtx'        : "androidx.paging:paging-runtime-ktx:2.1.2",
@@ -73,7 +76,9 @@ ext.libs = [
         ],
         dagger      : [
                 'dagger'                  : "com.google.dagger:dagger:$dagger",
-                'daggerCompiler'          : "com.google.dagger:dagger-compiler:$dagger"
+                'daggerCompiler'          : "com.google.dagger:dagger-compiler:$dagger",
+                'hilt'                    : "com.google.dagger:hilt-android:$dagger",
+                'hiltCompiler'            : "com.google.dagger:hilt-compiler:$dagger"
         ],
         squareup    : [
                 'moshi'                  : "com.squareup.moshi:moshi-adapters:$moshi",
@@ -100,7 +105,6 @@ ext.libs = [
                 'epoxyProcessor'         : "com.airbnb.android:epoxy-processor:$epoxy",
                 'epoxyPaging'            : "com.airbnb.android:epoxy-paging:$epoxy",
                 'mavericks'              : "com.airbnb.android:mavericks:$mavericks",
-                'mavericksRx'            : "com.airbnb.android:mavericks-rxjava2:$mavericks",
                 'mavericksTesting'       : "com.airbnb.android:mavericks-testing:$mavericks"
         ],
         mockk      : [
@@ -113,13 +117,13 @@ ext.libs = [
                 'bigImageViewer'         : "com.github.piasy:BigImageViewer:$bigImageViewer",
                 'glideImageLoader'       : "com.github.piasy:GlideImageLoader:$bigImageViewer",
                 'progressPieIndicator'   : "com.github.piasy:ProgressPieIndicator:$bigImageViewer",
-                'glideImageViewFactory'  : "com.github.piasy:GlideImageViewFactory:$bigImageViewer"
+                'glideImageViewFactory'  : "com.github.piasy:GlideImageViewFactory:$bigImageViewer",
+                'flowBinding'            : "io.github.reactivecircus.flowbinding:flowbinding-android:$flowBinding",
+                'flowBindingAppcompat'   : "io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowBinding",
+                'flowBindingMaterial'    : "io.github.reactivecircus.flowbinding:flowbinding-material:$flowBinding"
         ],
         jakewharton : [
-                'timber'                 : "com.jakewharton.timber:timber:5.0.1",
-                'rxbinding'              : "com.jakewharton.rxbinding3:rxbinding:$rxBinding",
-                'rxbindingAppcompat'     : "com.jakewharton.rxbinding3:rxbinding-appcompat:$rxBinding",
-                'rxbindingMaterial'      : "com.jakewharton.rxbinding3:rxbinding-material:$rxBinding"
+                'timber'                 : "com.jakewharton.timber:timber:5.0.1"
         ],
         jsonwebtoken: [
                 'jjwtApi'                : "io.jsonwebtoken:jjwt-api:$jjwt",
diff --git a/docs/hilt_migration.md b/docs/hilt_migration.md
new file mode 100644
index 0000000000..50021e9792
--- /dev/null
+++ b/docs/hilt_migration.md
@@ -0,0 +1,33 @@
+Useful links:
+- https://dagger.dev/hilt/migration-guide
+- https://dagger.dev/hilt/quick-start
+
+Hilt is built on top of Dagger 2 and simplify usage by removing needs to create components manually.
+
+When you create a new feature, you should have the following:
+
+Annotate your Activity with @AndroidEntryPoint
+If you have a BottomSheetFragment => Annotate it with @AndroidEntryPoint
+Otherwise => Add your Fragment to the FragmentModule
+Add your ViewModel.Factory to the MavericksViewModelModule
+Makes sure your ViewModel as the following code:
+
+```
+ @AssistedFactory
+    interface Factory: MavericksAssistedViewModelFactory<MyViewModel, MyViewState> {
+        override fun create(initialState: MyViewState): MyViewModel
+    }
+
+    companion object : MavericksViewModelFactory<MyViewModel, MyViewState> by hiltMavericksViewModelFactory()
+```
+
+## Some remarks
+
+@MavericksViewModelScope dependencies can't be injected inside Fragments/Activities
+You can only inject @Singleton, @MavericksViewModelScope or unscoped dependencies inside Maverick ViewModels
+You can access some specific dependencies from Singleton component by using
+```
+context.singletonEntryPoint()
+```
+Be aware that only the app has been migrated to Hilt and not the SDK.
+
diff --git a/docs/rx_flow_migration.md b/docs/rx_flow_migration.md
new file mode 100644
index 0000000000..a438b0f6fb
--- /dev/null
+++ b/docs/rx_flow_migration.md
@@ -0,0 +1,41 @@
+Useful links:
+- https://github.com/ReactiveCircus/FlowBinding
+- https://ivanisidrowu.github.io/kotlin/2020/08/09/Kotlin-Flow-Migration-And-Testing.html
+
+
+Rx is now completely removed from Element dependencies.
+Some examples of the changes:
+
+```
+         sharedActionViewModel
+                .observe()
+                .subscribe { handleQuickActions(it) }
+                .disposeOnDestroyView()
+ ```               
+     
+became 
+           
+ ```              
+         sharedActionViewModel 
+                .stream()
+                .onEach { handleQuickActions(it) }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
+
+```
+
+Inside fragment use  
+```
+launchIn(viewLifecycleOwner.lifecycleScope)
+```
+Inside activity use
+```
+launchIn(lifecycleScope)
+```
+Inside viewModel use
+```
+launchIn(viewModelScope)
+```
+
+Also be aware that when using these scopes the coroutine is launched on Dispatchers.Main by default.
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a37233c5e2..f5e3b23f79 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
+distributionSha256Sum=00b273629df4ce46e68df232161d5a7c4e495b9a029ce6e0420f071e21316867
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/library/ui-styles/src/main/res/color/form_edit_text_hint_color_selector.xml b/library/ui-styles/src/main/res/color/form_edit_text_hint_color_selector.xml
new file mode 100644
index 0000000000..343c42ebf3
--- /dev/null
+++ b/library/ui-styles/src/main/res/color/form_edit_text_hint_color_selector.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?vctr_content_tertiary" android:state_enabled="false" />
+    <item android:color="?vctr_content_tertiary" android:state_focused="false" />
+    <item android:color="?colorPrimary" />
+</selector>
diff --git a/library/ui-styles/src/main/res/color/form_edit_text_stroke_color_selector.xml b/library/ui-styles/src/main/res/color/form_edit_text_stroke_color_selector.xml
new file mode 100644
index 0000000000..7079cc271b
--- /dev/null
+++ b/library/ui-styles/src/main/res/color/form_edit_text_stroke_color_selector.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?colorPrimary" android:state_focused="true"/>
+    <item android:color="?colorPrimary" android:state_hovered="true"/>
+    <item android:color="?colorPrimary" android:state_enabled="false"/>
+    <item android:color="?vctr_content_quinary"/>
+</selector>
diff --git a/library/ui-styles/src/main/res/values/colors.xml b/library/ui-styles/src/main/res/values/colors.xml
index 03d1ff69db..9df2794a1a 100644
--- a/library/ui-styles/src/main/res/values/colors.xml
+++ b/library/ui-styles/src/main/res/values/colors.xml
@@ -129,9 +129,9 @@
     <color name="vctr_chat_effect_snow_background_light">@color/black_alpha</color>
     <color name="vctr_chat_effect_snow_background_dark">@android:color/transparent</color>
 
-    <attr name="vctr_voice_message_toast_background" format="color" />
-    <color name="vctr_voice_message_toast_background_light">@color/palette_black_900</color>
-    <color name="vctr_voice_message_toast_background_dark">@color/palette_gray_400</color>
+    <attr name="vctr_toast_background" format="color" />
+    <color name="vctr_toast_background_light">@color/palette_black_900</color>
+    <color name="vctr_toast_background_dark">@color/palette_gray_400</color>
 
     <!-- Presence Indicator colors -->
     <attr name="vctr_presence_indicator_offline" format="color" />
diff --git a/library/ui-styles/src/main/res/values/styles_buttons.xml b/library/ui-styles/src/main/res/values/styles_buttons.xml
index 2e41b663a4..e445dc5a1d 100644
--- a/library/ui-styles/src/main/res/values/styles_buttons.xml
+++ b/library/ui-styles/src/main/res/values/styles_buttons.xml
@@ -9,6 +9,11 @@
         <item name="lineHeight">24sp</item>
     </style>
 
+    <style name="Widget.Vector.Button.CallToAction" parent="Widget.Vector.Button">
+        <item name="android:backgroundTint">@color/button_background_tint_selector</item>
+        <item name="android:textColor">@android:color/white</item>
+    </style>
+
     <style name="Widget.Vector.Button.Destructive">
         <item name="android:minWidth">94dp</item>
         <item name="materialThemeOverlay">@style/VectorMaterialThemeOverlayDestructive</item>
diff --git a/library/ui-styles/src/main/res/values/styles_edit_text.xml b/library/ui-styles/src/main/res/values/styles_edit_text.xml
index cc1041a2ce..8de548dd03 100644
--- a/library/ui-styles/src/main/res/values/styles_edit_text.xml
+++ b/library/ui-styles/src/main/res/values/styles_edit_text.xml
@@ -1,14 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Default style for TextInputLayout -->
-    <style name="Widget.Vector.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox" />
-
-    <style name="Widget.Vector.TextInputLayout.Password">
-        <item name="endIconMode">password_toggle</item>
-        <item name="endIconTint">?vctr_content_secondary</item>
-    </style>
-
     <style name="Widget.Vector.EditText.Composer" parent="Widget.AppCompat.EditText">
         <item name="android:background">@android:color/transparent</item>
         <item name="android:inputType">textCapSentences|textMultiLine</item>
diff --git a/library/ui-styles/src/main/res/values/styles_text_input_layout.xml b/library/ui-styles/src/main/res/values/styles_text_input_layout.xml
new file mode 100644
index 0000000000..95a406ea5c
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/styles_text_input_layout.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <!-- Default style for TextInputLayout -->
+    <style name="Widget.Vector.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox" />
+
+    <style name="Widget.Vector.TextInputLayout.Password">
+        <item name="endIconMode">password_toggle</item>
+        <item name="endIconTint">?vctr_content_secondary</item>
+    </style>
+
+    <style name="Widget.Vector.TextInputLayout.Form">
+        <item name="boxStrokeColor">@color/form_edit_text_stroke_color_selector</item>
+        <item name="android:textColorHint">@color/form_edit_text_hint_color_selector</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/values/styles_toast.xml b/library/ui-styles/src/main/res/values/styles_toast.xml
new file mode 100644
index 0000000000..22f4da7ac0
--- /dev/null
+++ b/library/ui-styles/src/main/res/values/styles_toast.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="Widget.Vector.TextView.Caption.Toast">
+        <item name="android:paddingTop">8dp</item>
+        <item name="android:paddingBottom">8dp</item>
+        <item name="android:paddingStart">12dp</item>
+        <item name="android:paddingEnd">12dp</item>
+        <item name="android:background">@drawable/bg_round_corner_8dp</item>
+        <item name="android:backgroundTint">?vctr_toast_background</item>
+        <item name="android:textColor">@color/palette_white</item>
+        <item name="android:gravity">center</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/values/styles_voice_message.xml b/library/ui-styles/src/main/res/values/styles_voice_message.xml
index 59fea75074..2e87353303 100644
--- a/library/ui-styles/src/main/res/values/styles_voice_message.xml
+++ b/library/ui-styles/src/main/res/values/styles_voice_message.xml
@@ -12,15 +12,4 @@
         <item name="direction">rightToLeft</item>
     </style>
 
-    <style name="Widget.Vector.TextView.Caption.Toast">
-        <item name="android:paddingTop">8dp</item>
-        <item name="android:paddingBottom">8dp</item>
-        <item name="android:paddingStart">12dp</item>
-        <item name="android:paddingEnd">12dp</item>
-        <item name="android:background">@drawable/bg_round_corner_8dp</item>
-        <item name="android:backgroundTint">?vctr_voice_message_toast_background</item>
-        <item name="android:textColor">@color/palette_white</item>
-        <item name="android:gravity">center</item>
-    </style>
-
 </resources>
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/values/theme_dark.xml b/library/ui-styles/src/main/res/values/theme_dark.xml
index 03a47f55bf..3f256c0170 100644
--- a/library/ui-styles/src/main/res/values/theme_dark.xml
+++ b/library/ui-styles/src/main/res/values/theme_dark.xml
@@ -176,8 +176,7 @@
         <!-- Keywords -->
         <item name="vctr_keyword_style">@style/Widget.Vector.Keyword</item>
 
-        <!-- Voice Message -->
-        <item name="vctr_voice_message_toast_background">@color/vctr_voice_message_toast_background_dark</item>
+        <item name="vctr_toast_background">@color/vctr_toast_background_dark</item>
     </style>
 
     <style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />
diff --git a/library/ui-styles/src/main/res/values/theme_light.xml b/library/ui-styles/src/main/res/values/theme_light.xml
index c8f0629313..cf9da4de8f 100644
--- a/library/ui-styles/src/main/res/values/theme_light.xml
+++ b/library/ui-styles/src/main/res/values/theme_light.xml
@@ -179,8 +179,7 @@
         <!-- Keywords -->
         <item name="vctr_keyword_style">@style/Widget.Vector.Keyword</item>
 
-        <!-- Voice Message -->
-        <item name="vctr_voice_message_toast_background">@color/vctr_voice_message_toast_background_light</item>
+        <item name="vctr_toast_background">@color/vctr_toast_background_light</item>
     </style>
 
     <style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />
diff --git a/library/ui-styles/src/main/res/values/theme_sc.xml b/library/ui-styles/src/main/res/values/theme_sc.xml
index c72e6e177a..4e7fd1d3cc 100644
--- a/library/ui-styles/src/main/res/values/theme_sc.xml
+++ b/library/ui-styles/src/main/res/values/theme_sc.xml
@@ -121,7 +121,7 @@
         <item name="vctr_jump_to_unread_style">@style/Widget.Vector.JumpToUnread.SC.Dark</item>
 
         <!-- Voice Message -->
-        <item name="vctr_voice_message_toast_background">?colorBackgroundFloating</item>
+        <item name="vctr_toast_background">?colorBackgroundFloating</item>
     </style>
 
     <style name="AppTheme.Base.SC.Dark">
diff --git a/library/ui-styles/src/main/res/values/theme_sc_light.xml b/library/ui-styles/src/main/res/values/theme_sc_light.xml
index 6807ae91f2..51d30f3c69 100644
--- a/library/ui-styles/src/main/res/values/theme_sc_light.xml
+++ b/library/ui-styles/src/main/res/values/theme_sc_light.xml
@@ -117,7 +117,7 @@
         <item name="vctr_jump_to_unread_style">@style/Widget.Vector.JumpToUnread.SC.Light</item>
 
         <!-- Voice Message -->
-        <item name="vctr_voice_message_toast_background">@color/background_floating_sc</item> <!-- needs dark background -->
+        <item name="vctr_toast_background">@color/background_floating_sc</item> <!-- needs dark background -->
     </style>
 
     <!-- Default AppTheme for usage where settings don't apply -->
diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt
index 13fd097bcd..2a0abd3d24 100644
--- a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt
+++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt
@@ -27,6 +27,7 @@ import org.matrix.android.sdk.api.session.group.GroupSummaryQueryParams
 import org.matrix.android.sdk.api.session.group.model.GroupSummary
 import org.matrix.android.sdk.api.session.identity.ThreePid
 import org.matrix.android.sdk.api.session.pushers.Pusher
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
 import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
 import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
@@ -44,10 +45,10 @@ import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
 
 class FlowSession(private val session: Session) {
 
-    fun liveRoomSummaries(queryParams: RoomSummaryQueryParams): Flow<List<RoomSummary>> {
-        return session.getRoomSummariesLive(queryParams).asFlow()
+    fun liveRoomSummaries(queryParams: RoomSummaryQueryParams, sortOrder: RoomSortOrder = RoomSortOrder.NONE): Flow<List<RoomSummary>> {
+        return session.getRoomSummariesLive(queryParams, sortOrder).asFlow()
                 .startWith(session.coroutineDispatchers.io) {
-                    session.getRoomSummaries(queryParams)
+                    session.getRoomSummaries(queryParams, sortOrder)
                 }
     }
 
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 45082c9a23..d92da9688b 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -9,7 +9,7 @@ buildscript {
         mavenCentral()
     }
     dependencies {
-        classpath "io.realm:realm-gradle-plugin:10.8.0"
+        classpath "io.realm:realm-gradle-plugin:10.8.1"
     }
 }
 
@@ -31,7 +31,7 @@ android {
         // that the app's state is completely cleared between tests.
         testInstrumentationRunnerArguments clearPackageData: 'true'
 
-        buildConfigField "String", "SDK_VERSION", "\"1.3.6\""
+        buildConfigField "String", "SDK_VERSION", "\"1.3.8\""
 
         buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
         resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
@@ -44,6 +44,7 @@ android {
     }
 
     testOptions {
+        // Comment to run on Android 12
         execution 'ANDROIDX_TEST_ORCHESTRATOR'
     }
 
@@ -106,8 +107,9 @@ dependencies {
     implementation libs.androidx.appCompat
     implementation libs.androidx.core
 
-    implementation libs.androidx.lifecycleExtensions
-    implementation  libs.androidx.lifecycleJava8
+    // Lifecycle
+    implementation libs.androidx.lifecycleCommon
+    implementation libs.androidx.lifecycleProcess
 
     // Network
     implementation libs.squareup.retrofit
@@ -156,10 +158,10 @@ dependencies {
     implementation libs.apache.commonsImaging
 
     // Phone number https://github.com/google/libphonenumber
-    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.35'
+    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.37'
 
     testImplementation libs.tests.junit
-    testImplementation 'org.robolectric:robolectric:4.6.1'
+    testImplementation 'org.robolectric:robolectric:4.7'
     //testImplementation 'org.robolectric:shadows-support-v4:3.0'
     // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
     testImplementation libs.mockk.mockk
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
index 3359e253f6..306ed45500 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
@@ -16,6 +16,7 @@
 
 package org.matrix.android.sdk.api
 
+import okhttp3.ConnectionSpec
 import org.matrix.android.sdk.api.crypto.MXCryptoConfig
 import java.net.Proxy
 
@@ -44,6 +45,10 @@ data class MatrixConfiguration(
          * You can create one using for instance Proxy(proxyType, InetSocketAddress.createUnresolved(hostname, port).
          */
         val proxy: Proxy? = null,
+        /**
+         * TLS versions and cipher suites limitation for unauthenticated requests
+         */
+        val connectionSpec: ConnectionSpec = ConnectionSpec.RESTRICTED_TLS,
         /**
          * True to advertise support for call transfers to other parties on Matrix calls.
          */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt
index dc4e0f152d..4a41eaec4a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt
@@ -20,7 +20,18 @@ package org.matrix.android.sdk.api
  * This class contains pattern to match Matrix Url, aka mxc urls
  */
 object MatrixUrls {
+    /**
+     * "mxc" scheme, including "://". So "mxc://"
+     */
     const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
 
+    /**
+     * Return true if the String starts with "mxc://"
+     */
     fun String.isMxcUrl() = startsWith(MATRIX_CONTENT_URI_SCHEME)
+
+    /**
+     * Remove the "mxc://" prefix. No op if the String is not a Mxc URL
+     */
+    fun String.removeMxcPrefix() = removePrefix(MATRIX_CONTENT_URI_SCHEME)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
index 5e35917243..9cb784c9c0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
@@ -105,9 +105,15 @@ interface AuthenticationService {
     /**
      * Authenticate with a matrixId and a password
      * Usually call this after a successful call to getWellKnownData()
+     * @param homeServerConnectionConfig the information about the homeserver and other configuration
+     * @param matrixId the matrixId of the user
+     * @param password the password of the account
+     * @param initialDeviceName the initial device name
+     * @param deviceId the device id, optional. If not provided or null, the server will generate one.
      */
     suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
                                      matrixId: String,
                                      password: String,
-                                     initialDeviceName: String): Session
+                                     initialDeviceName: String,
+                                     deviceId: String? = null): Session
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt
index 215f0a0351..e87824d6a5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.api.auth.data
 import android.net.Uri
 import com.squareup.moshi.JsonClass
 import okhttp3.CipherSuite
+import okhttp3.ConnectionSpec
 import okhttp3.TlsVersion
 import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig.Builder
 import org.matrix.android.sdk.internal.network.ssl.Fingerprint
@@ -191,32 +192,25 @@ data class HomeServerConnectionConfig(
         /**
          * Convenient method to limit the TLS versions and cipher suites for this Builder
          * Ref:
-         * - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf
+         * - https://www.ssi.gouv.fr/uploads/2017/07/anssi-guide-recommandations_de_securite_relatives_a_tls-v1.2.pdf
          * - https://developer.android.com/reference/javax/net/ssl/SSLEngine
          *
          * @param tlsLimitations         true to use Tls limitations
          * @param enableCompatibilityMode set to true for Android < 20
          * @return this builder
          */
+        @Deprecated("TLS versions and cipher suites are limited by default")
         fun withTlsLimitations(tlsLimitations: Boolean, enableCompatibilityMode: Boolean): Builder {
             if (tlsLimitations) {
                 withShouldAcceptTlsExtensions(false)
 
-                // Tls versions
-                addAcceptedTlsVersion(TlsVersion.TLS_1_2)
-                addAcceptedTlsVersion(TlsVersion.TLS_1_3)
+                // TlS versions
+                ConnectionSpec.RESTRICTED_TLS.tlsVersions?.let { this.tlsVersions.addAll(it) }
 
                 forceUsageOfTlsVersions(enableCompatibilityMode)
 
                 // Cipher suites
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)
-                addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256)
+                ConnectionSpec.RESTRICTED_TLS.cipherSuites?.let { this.tlsCipherSuites.addAll(it) }
 
                 if (enableCompatibilityMode) {
                     // Adopt some preceding cipher suites for Android < 20 to be able to negotiate
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
index a2a9373837..247d58ce79 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
@@ -17,6 +17,7 @@
 package org.matrix.android.sdk.api.auth.login
 
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.util.JsonDict
 
 /**
  * Set of methods to be able to login to an existing account on a homeserver.
@@ -34,12 +35,14 @@ interface LoginWizard {
      *
      * @param login the login field. Can be a user name, or a msisdn (email or phone number) associated to the account
      * @param password the password of the account
-     * @param deviceName the initial device name
+     * @param initialDeviceName the initial device name
+     * @param deviceId the device id, optional. If not provided or null, the server will generate one.
      * @return a [Session] if the login is successful
      */
     suspend fun login(login: String,
                       password: String,
-                      deviceName: String): Session
+                      initialDeviceName: String,
+                      deviceId: String? = null): Session
 
     /**
      * Exchange a login token to an access token.
@@ -49,6 +52,12 @@ interface LoginWizard {
      */
     suspend fun loginWithToken(loginToken: String): Session
 
+    /**
+     * Login to the homeserver by sending a custom JsonDict.
+     * The data should contain at least one entry "type" with a String value.
+     */
+    suspend fun loginCustom(data: JsonDict): Session
+
     /**
      * Ask the homeserver to reset the user password. The password will not be reset until
      * [resetPasswordMailConfirmed] is successfully called.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
index b2035bb2eb..13a26c89c1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
@@ -18,6 +18,8 @@ package org.matrix.android.sdk.api.failure
 
 import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
 import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerError
+import org.matrix.android.sdk.api.session.contentscanner.ScanFailure
 import org.matrix.android.sdk.internal.di.MoshiProvider
 import java.io.IOException
 import javax.net.ssl.HttpsURLConnection
@@ -100,3 +102,19 @@ fun Throwable.isRegistrationAvailabilityError(): Boolean {
             error.code == MatrixError.M_INVALID_USERNAME ||
             error.code == MatrixError.M_EXCLUSIVE)
 }
+
+/**
+ * Try to convert to a ScanFailure. Return null in the cases it's not possible
+ */
+fun Throwable.toScanFailure(): ScanFailure? {
+    return if (this is Failure.OtherServerError) {
+        tryOrNull {
+            MoshiProvider.providesMoshi()
+                    .adapter(ContentScannerError::class.java)
+                    .fromJson(errorBody)
+        }
+                ?.let { ScanFailure(it, httpCode, this) }
+    } else {
+        null
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/utils/DefaultSubscriber.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushEvents.kt
similarity index 55%
rename from vector/src/main/java/im/vector/app/core/utils/DefaultSubscriber.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushEvents.kt
index a82e5a4e03..466e345cad 100644
--- a/vector/src/main/java/im/vector/app/core/utils/DefaultSubscriber.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushEvents.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 New Vector Ltd
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,19 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.matrix.android.sdk.api.pushrules
 
-package im.vector.app.core.utils
+import org.matrix.android.sdk.api.pushrules.rest.PushRule
+import org.matrix.android.sdk.api.session.events.model.Event
 
-import io.reactivex.Completable
-import io.reactivex.Single
-import io.reactivex.disposables.Disposable
-import io.reactivex.internal.functions.Functions
-import timber.log.Timber
-
-fun <T> Single<T>.subscribeLogError(): Disposable {
-    return subscribe(Functions.emptyConsumer(), { Timber.e(it) })
-}
-
-fun Completable.subscribeLogError(): Disposable {
-    return subscribe({}, { Timber.e(it) })
-}
+data class PushEvents(
+        val matchedEvents: List<Pair<Event, PushRule>>,
+        val roomsJoined: Collection<String>,
+        val roomsLeft: Collection<String>,
+        val redactedEventIds: List<String>
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt
index 1d0acf38fa..88268f0f86 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt
@@ -51,11 +51,7 @@ interface PushRuleService {
 //    fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule?
 
     interface PushRuleListener {
-        fun onMatchRule(event: Event, actions: List<Action>)
-        fun onRoomJoined(roomId: String)
-        fun onRoomLeft(roomId: String)
-        fun onEventRedacted(redactedEventId: String)
-        fun batchFinish()
+        fun onEvents(pushEvents: PushEvents)
     }
 
     fun getKeywords(): LiveData<Set<String>>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
index 8f83beface..31ec131c5c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
@@ -19,17 +19,41 @@ package org.matrix.android.sdk.api.query
 /**
  * Basic query language. All these cases are mutually exclusive.
  */
-sealed class QueryStringValue {
-    object NoCondition : QueryStringValue()
-    object IsNull : QueryStringValue()
-    object IsNotNull : QueryStringValue()
-    object IsEmpty : QueryStringValue()
-    object IsNotEmpty : QueryStringValue()
-    data class Equals(val string: String, val case: Case = Case.SENSITIVE) : QueryStringValue()
-    data class Contains(val string: String, val case: Case = Case.SENSITIVE) : QueryStringValue()
+sealed interface QueryStringValue {
+    sealed interface ContentQueryStringValue : QueryStringValue {
+        val string: String
+        val case: Case
+    }
+
+    object NoCondition : QueryStringValue
+    object IsNull : QueryStringValue
+    object IsNotNull : QueryStringValue
+    object IsEmpty : QueryStringValue
+    object IsNotEmpty : QueryStringValue
+
+    data class Equals(override val string: String, override val case: Case = Case.SENSITIVE) : ContentQueryStringValue
+    data class Contains(override val string: String, override val case: Case = Case.SENSITIVE) : ContentQueryStringValue
 
     enum class Case {
+        /**
+         * Match query sensitive to case
+         */
         SENSITIVE,
-        INSENSITIVE
+
+        /**
+         * Match query insensitive to case, this only works for Latin-1 character sets
+         */
+        INSENSITIVE,
+
+        /**
+         * Match query with input normalized (case insensitive)
+         * Works around Realms inability to sort or filter by case for non Latin-1 character sets
+         * Expects the target field to contain normalized data
+         *
+         * @see org.matrix.android.sdk.internal.util.Normalizer.normalize
+         */
+        NORMALIZED
     }
 }
+
+internal fun QueryStringValue.isNormalized() = this is QueryStringValue.ContentQueryStringValue && case == QueryStringValue.Case.NORMALIZED
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
index d4bfd4ee8c..3f817ec4d2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
@@ -31,6 +31,7 @@ import org.matrix.android.sdk.api.session.cache.CacheService
 import org.matrix.android.sdk.api.session.call.CallSignalingService
 import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
 import org.matrix.android.sdk.api.session.crypto.CryptoService
 import org.matrix.android.sdk.api.session.events.EventService
 import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
@@ -120,9 +121,11 @@ interface Session :
     fun requireBackgroundSync()
 
     /**
-     * Launches infinite periodic background syncs
-     * This does not work in doze mode :/
-     * If battery optimization is on it can work in app standby but that's all :/
+     * Launches infinite self rescheduling background syncs via the WorkManager
+     *
+     * While dozing, syncs will only occur during maintenance windows
+     * For reliability it's recommended to also start a long running foreground service
+     * along with disabling battery optimizations
      */
     fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
 
@@ -190,6 +193,11 @@ interface Session :
      */
     fun cryptoService(): CryptoService
 
+    /**
+     * Returns the ContentScannerService associated with the session
+     */
+    fun contentScannerService(): ContentScannerService
+
     /**
      * Returns the identity service associated with the session
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt
index 36c471bb2b..3dd096e144 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt
@@ -16,6 +16,8 @@
 
 package org.matrix.android.sdk.api.session.content
 
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+
 /**
  * This interface defines methods for accessing content from the current session.
  */
@@ -39,6 +41,15 @@ interface ContentUrlResolver {
      */
     fun resolveFullSize(contentUrl: String?): String?
 
+    /**
+     * Get the ResolvedMethod to download a URL
+     *
+     * @param contentUrl  the Matrix media content URI (in the form of "mxc://...").
+     * @param elementToDecrypt Encryption data may be required if you use a content scanner
+     * @return the Method to access resource, or null if invalid
+     */
+    fun resolveForDownload(contentUrl: String?, elementToDecrypt: ElementToDecrypt? = null): ResolvedMethod?
+
     /**
      * Get the actual URL for accessing the thumbnail image of a given Matrix media content URI.
      *
@@ -49,4 +60,9 @@ interface ContentUrlResolver {
      * @return the URL to access the described resource, or null if the url is invalid.
      */
     fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String?
+
+    sealed class ResolvedMethod {
+        data class GET(val url: String) : ResolvedMethod()
+        data class POST(val url: String, val jsonBody: String) : ResolvedMethod()
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerError.kt
new file mode 100644
index 0000000000..cef5d41f2c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerError.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.contentscanner
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class ContentScannerError(
+        @Json(name = "info") val info: String? = null,
+        @Json(name = "reason") val reason: String? = null
+) {
+    companion object {
+        // 502 The server failed to request media from the media repo.
+        const val REASON_MCS_MEDIA_REQUEST_FAILED = "MCS_MEDIA_REQUEST_FAILED"
+
+        /* 400 The server failed to decrypt the encrypted media downloaded from the media repo.*/
+        const val REASON_MCS_MEDIA_FAILED_TO_DECRYPT = "MCS_MEDIA_FAILED_TO_DECRYPT"
+
+        /* 403 The server scanned the downloaded media but the antivirus script returned a non-zero exit code.*/
+        const val REASON_MCS_MEDIA_NOT_CLEAN = "MCS_MEDIA_NOT_CLEAN"
+
+        /* 403 The provided encrypted_body could not be decrypted. The client should request the public key of the server and then retry (once).*/
+        const val REASON_MCS_BAD_DECRYPTION = "MCS_BAD_DECRYPTION"
+
+        /* 400 The request body contains malformed JSON.*/
+        const val REASON_MCS_MALFORMED_JSON = "MCS_MALFORMED_JSON"
+    }
+}
+
+class ScanFailure(val error: ContentScannerError, val httpCode: Int, cause: Throwable? = null) : Throwable(cause = cause)
+
+// For Glide, which deals with Exception and not with Throwable
+fun ScanFailure.toException() = Exception(this)
+fun Throwable.toScanFailure() = this.cause as? ScanFailure
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt
new file mode 100644
index 0000000000..1dd7bab01c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.contentscanner
+
+import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+
+interface ContentScannerService {
+
+    val serverPublicKey: String?
+
+    fun getContentScannerServer(): String?
+    fun setScannerUrl(url: String?)
+    fun enableScanner(enabled: Boolean)
+    fun isScannerEnabled(): Boolean
+    fun getLiveStatusForFile(mxcUrl: String, fetchIfNeeded: Boolean = true, fileInfo: ElementToDecrypt? = null): LiveData<Optional<ScanStatusInfo>>
+    fun getCachedScanResultForFile(mxcUrl: String): ScanStatusInfo?
+
+    /**
+     * Get the current public curve25519 key that the AV server is advertising.
+     * @param callback on success callback containing the server public key
+     */
+    suspend fun getServerPublicKey(forceDownload: Boolean = false): String?
+    suspend fun getScanResultForAttachment(mxcUrl: String, fileInfo: ElementToDecrypt? = null): ScanStatusInfo
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ScanState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ScanState.kt
new file mode 100644
index 0000000000..da209080ac
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ScanState.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.contentscanner
+
+enum class ScanState {
+    TRUSTED,
+    INFECTED,
+    UNKNOWN,
+    IN_PROGRESS
+}
+
+data class ScanStatusInfo(
+        val state: ScanState,
+        val scanDateTimestamp: Long?,
+        val humanReadableMessage: String?
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
index 169f90dbca..aad5fce33e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
@@ -22,6 +22,8 @@ import org.json.JSONObject
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageType
 import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
@@ -310,3 +312,6 @@ fun Event.isEdition(): Boolean {
 fun Event.getPresenceContent(): PresenceContent? {
     return content.toModel<PresenceContent>()
 }
+
+fun Event.isInvitation(): Boolean = type == EventType.STATE_ROOM_MEMBER &&
+        content?.toModel<RoomMemberContent>()?.membership == Membership.INVITE
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
index d0ce55070e..a39ca5b4f4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
@@ -102,6 +102,9 @@ object EventType {
     // Relation Events
     const val REACTION = "m.reaction"
 
+    // Poll
+    const val POLL_START = "org.matrix.msc3381.poll.start"
+
     // Unwedging
     internal const val DUMMY = "m.dummy"
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
index d80faa729c..e4bd498990 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
@@ -94,13 +94,15 @@ interface RoomService {
      * Get a snapshot list of room summaries.
      * @return the immutable list of [RoomSummary]
      */
-    fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List<RoomSummary>
+    fun getRoomSummaries(queryParams: RoomSummaryQueryParams,
+                         sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary>
 
     /**
      * Get a live list of room summaries. This list is refreshed as soon as the data changes.
      * @return the [LiveData] of List[RoomSummary]
      */
-    fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>>
+    fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams,
+                             sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<List<RoomSummary>>
 
     /**
      * Get a snapshot list of Breadcrumbs
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt
new file mode 100644
index 0000000000..ef2fd1867a
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room.model.message
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class MessagePollContent(
+    @Json(name = "org.matrix.msc3381.poll.start") val pollCreationInfo: PollCreationInfo? = null
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollAnswer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollAnswer.kt
new file mode 100644
index 0000000000..8f5ff53c85
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollAnswer.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room.model.message
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class PollAnswer(
+        @Json(name = "id") val id: String? = null,
+        @Json(name = "org.matrix.msc1767.text") val answer: String? = null
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt
new file mode 100644
index 0000000000..e652514b92
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollCreationInfo.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room.model.message
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class PollCreationInfo(
+    @Json(name = "question") val question: PollQuestion? = null,
+    @Json(name = "kind") val kind: String? = "org.matrix.msc3381.poll.disclosed",
+    @Json(name = "max_selections") val maxSelections: Int = 1,
+    @Json(name = "answers") val answers: List<PollAnswer>? = null
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollQuestion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollQuestion.kt
new file mode 100644
index 0000000000..76025f745e
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/PollQuestion.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.room.model.message
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class PollQuestion(
+        @Json(name = "org.matrix.msc1767.text") val question: String? = null
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
index 6ae42de90c..a2b38b6606 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
@@ -20,7 +20,6 @@ import org.matrix.android.sdk.api.session.content.ContentAttachmentData
 import org.matrix.android.sdk.api.session.events.model.Content
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.room.model.message.MessageType
-import org.matrix.android.sdk.api.session.room.model.message.OptionItem
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.util.Cancelable
 
@@ -84,10 +83,10 @@ interface SendService {
     /**
      * Send a poll to the room.
      * @param question the question
-     * @param options list of (label, value)
+     * @param options list of options
      * @return a [Cancelable]
      */
-    fun sendPoll(question: String, options: List<OptionItem>): Cancelable
+    fun sendPoll(question: String, options: List<String>): Cancelable
 
     /**
      * Method to send a poll response.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt
index 4a6462477d..86cb10bfe8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt
@@ -28,8 +28,10 @@ import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
 import org.matrix.android.sdk.api.session.room.model.ReadReceipt
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
 import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
 import org.matrix.android.sdk.api.session.room.sender.SenderInfo
+import org.matrix.android.sdk.api.util.ContentUtils
 import org.matrix.android.sdk.api.util.ContentUtils.extractUsefulTextFromReply
 
 /**
@@ -131,20 +133,6 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? {
     }
 }
 
-/**
- * Get last Message body, after a possible edition
- */
-fun TimelineEvent.getLastMessageBody(): String? {
-    val lastMessageContent = getLastMessageContent()
-
-    if (lastMessageContent != null) {
-        return lastMessageContent.newContent?.toModel<MessageContent>()?.body
-                ?: lastMessageContent.body
-    }
-
-    return null
-}
-
 /**
  * Returns true if it's a reply
  */
@@ -156,11 +144,25 @@ fun TimelineEvent.isEdition(): Boolean {
     return root.isEdition()
 }
 
-fun TimelineEvent.getTextEditableContent(): String? {
-    val lastContent = getLastMessageContent()
+/**
+ * Get the latest message body, after a possible edition, stripping the reply prefix if necessary
+ */
+fun TimelineEvent.getTextEditableContent(): String {
+    val lastContentBody = getLastMessageContent()?.body ?: return ""
     return if (isReply()) {
-        return extractUsefulTextFromReply(lastContent?.body ?: "")
+        extractUsefulTextFromReply(lastContentBody)
     } else {
-        lastContent?.body ?: ""
+        lastContentBody
     }
 }
+
+/**
+ * Get the latest displayable content.
+ * Will take care to hide spoiler text
+ */
+fun MessageContent.getTextDisplayableContent(): String {
+    return newContent?.toModel<MessageTextContent>()?.matrixFormattedBody?.let { ContentUtils.formatSpoilerTextFromHtml(it) }
+            ?: newContent?.toModel<MessageContent>()?.body
+            ?: (this as MessageTextContent?)?.matrixFormattedBody?.let { ContentUtils.formatSpoilerTextFromHtml(it) }
+            ?: body
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
index f40572518f..357c0b941a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.api.session.space
 import android.net.Uri
 import androidx.lifecycle.LiveData
 import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
 import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.internal.session.space.peeking.SpacePeekResult
@@ -74,9 +75,11 @@ interface SpaceService {
      * Get a live list of space summaries. This list is refreshed as soon as the data changes.
      * @return the [LiveData] of List[SpaceSummary]
      */
-    fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData<List<RoomSummary>>
+    fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams,
+                              sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>>
 
-    fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams): List<RoomSummary>
+    fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams,
+                          sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary>
 
     suspend fun joinSpace(spaceIdOrAlias: String,
                           reason: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/ContentUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/ContentUtils.kt
index 1a00b85ff4..e453cb2df5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/ContentUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/ContentUtils.kt
@@ -15,6 +15,8 @@
  */
 package org.matrix.android.sdk.api.util
 
+import org.matrix.android.sdk.internal.util.unescapeHtml
+
 object ContentUtils {
     fun extractUsefulTextFromReply(repliedBody: String): String {
         val lines = repliedBody.lines()
@@ -44,4 +46,15 @@ object ContentUtils {
         }
         return repliedBody
     }
+
+    @Suppress("RegExpRedundantEscape")
+    fun formatSpoilerTextFromHtml(formattedBody: String): String {
+        // var reason = "",
+        // can capture the spoiler reason for better formatting? ex. { reason = it.value;  ">"}
+        return formattedBody.replace("(?<=<span data-mx-spoiler)=\\\".+?\\\">".toRegex(), ">")
+                .replace("(?<=<span data-mx-spoiler>).+?(?=</span>)".toRegex()) { SPOILER_CHAR.repeat(it.value.length) }
+                .unescapeHtml()
+    }
+
+    private const val SPOILER_CHAR = "█"
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
index c746ad863a..934d61de45 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
@@ -51,6 +51,11 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M
         }
     }
 
+    fun stopSession(sessionId: String) {
+        val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId")
+        sessionComponent.session().stopSync()
+    }
+
     fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
         return sessionComponents.getOrPut(sessionParams.credentials.sessionId()) {
             DaggerSessionComponent
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
index 50d9e5a06c..554e21ce55 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
@@ -121,6 +121,10 @@ internal interface AuthAPI {
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "login")
     suspend fun login(@Body loginParams: TokenLoginParams): Credentials
 
+    @Headers("CONNECT_TIMEOUT:60000", "READ_TIMEOUT:60000", "WRITE_TIMEOUT:60000")
+    @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "login")
+    suspend fun login(@Body loginParams: JsonDict): Credentials
+
     /**
      * Ask the homeserver to reset the password associated with the provided email.
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
index 641a8f1bb6..8784d85c10 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
@@ -388,8 +388,15 @@ internal class DefaultAuthenticationService @Inject constructor(
     override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
                                               matrixId: String,
                                               password: String,
-                                              initialDeviceName: String): Session {
-        return directLoginTask.execute(DirectLoginTask.Params(homeServerConnectionConfig, matrixId, password, initialDeviceName))
+                                              initialDeviceName: String,
+                                              deviceId: String?): Session {
+        return directLoginTask.execute(DirectLoginTask.Params(
+                homeServerConnectionConfig = homeServerConnectionConfig,
+                userId = matrixId,
+                password = password,
+                deviceName = initialDeviceName,
+                deviceId = deviceId
+        ))
     }
 
     private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt
index d4b14f1ca9..5be480f633 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt
@@ -49,51 +49,54 @@ internal data class PasswordLoginParams(
 
         fun userIdentifier(user: String,
                            password: String,
-                           deviceDisplayName: String? = null,
-                           deviceId: String? = null): PasswordLoginParams {
+                           deviceDisplayName: String?,
+                           deviceId: String?): PasswordLoginParams {
             return PasswordLoginParams(
-                    mapOf(
+                    identifier = mapOf(
                             IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_USER,
                             IDENTIFIER_KEY_USER to user
                     ),
-                    password,
-                    LoginFlowTypes.PASSWORD,
-                    deviceDisplayName,
-                    deviceId)
+                    password = password,
+                    type = LoginFlowTypes.PASSWORD,
+                    deviceDisplayName = deviceDisplayName,
+                    deviceId = deviceId
+            )
         }
 
         fun thirdPartyIdentifier(medium: String,
                                  address: String,
                                  password: String,
-                                 deviceDisplayName: String? = null,
-                                 deviceId: String? = null): PasswordLoginParams {
+                                 deviceDisplayName: String?,
+                                 deviceId: String?): PasswordLoginParams {
             return PasswordLoginParams(
-                    mapOf(
+                    identifier = mapOf(
                             IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_THIRD_PARTY,
                             IDENTIFIER_KEY_MEDIUM to medium,
                             IDENTIFIER_KEY_ADDRESS to address
                     ),
-                    password,
-                    LoginFlowTypes.PASSWORD,
-                    deviceDisplayName,
-                    deviceId)
+                    password = password,
+                    type = LoginFlowTypes.PASSWORD,
+                    deviceDisplayName = deviceDisplayName,
+                    deviceId = deviceId
+            )
         }
 
         fun phoneIdentifier(country: String,
                             phone: String,
                             password: String,
-                            deviceDisplayName: String? = null,
-                            deviceId: String? = null): PasswordLoginParams {
+                            deviceDisplayName: String?,
+                            deviceId: String?): PasswordLoginParams {
             return PasswordLoginParams(
-                    mapOf(
+                    identifier = mapOf(
                             IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_PHONE,
                             IDENTIFIER_KEY_COUNTRY to country,
                             IDENTIFIER_KEY_PHONE to phone
                     ),
-                    password,
-                    LoginFlowTypes.PASSWORD,
-                    deviceDisplayName,
-                    deviceId)
+                    password = password,
+                    type = LoginFlowTypes.PASSWORD,
+                    deviceDisplayName = deviceDisplayName,
+                    deviceId = deviceId
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
index 854caf8a62..0583951138 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
@@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.auth.login.LoginProfileInfo
 import org.matrix.android.sdk.api.auth.login.LoginWizard
 import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.util.JsonDict
 import org.matrix.android.sdk.internal.auth.AuthAPI
 import org.matrix.android.sdk.internal.auth.PendingSessionStore
 import org.matrix.android.sdk.internal.auth.SessionCreator
@@ -32,6 +33,7 @@ import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistration
 import org.matrix.android.sdk.internal.auth.registration.RegisterAddThreePidTask
 import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.session.content.DefaultContentUrlResolver
+import org.matrix.android.sdk.internal.session.contentscanner.DisabledContentScannerService
 
 internal class DefaultLoginWizard(
         private val authAPI: AuthAPI,
@@ -43,7 +45,7 @@ internal class DefaultLoginWizard(
 
     private val getProfileTask: GetProfileTask = DefaultGetProfileTask(
             authAPI,
-            DefaultContentUrlResolver(pendingSessionData.homeServerConnectionConfig)
+            DefaultContentUrlResolver(pendingSessionData.homeServerConnectionConfig, DisabledContentScannerService())
     )
 
     override suspend fun getProfileInfo(matrixId: String): LoginProfileInfo {
@@ -52,11 +54,23 @@ internal class DefaultLoginWizard(
 
     override suspend fun login(login: String,
                                password: String,
-                               deviceName: String): Session {
+                               initialDeviceName: String,
+                               deviceId: String?): Session {
         val loginParams = if (Patterns.EMAIL_ADDRESS.matcher(login).matches()) {
-            PasswordLoginParams.thirdPartyIdentifier(ThreePidMedium.EMAIL, login, password, deviceName)
+            PasswordLoginParams.thirdPartyIdentifier(
+                    medium = ThreePidMedium.EMAIL,
+                    address = login,
+                    password = password,
+                    deviceDisplayName = initialDeviceName,
+                    deviceId = deviceId
+            )
         } else {
-            PasswordLoginParams.userIdentifier(login, password, deviceName)
+            PasswordLoginParams.userIdentifier(
+                    user = login,
+                    password = password,
+                    deviceDisplayName = initialDeviceName,
+                    deviceId = deviceId
+            )
         }
         val credentials = executeRequest(null) {
             authAPI.login(loginParams)
@@ -79,6 +93,14 @@ internal class DefaultLoginWizard(
         return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
     }
 
+    override suspend fun loginCustom(data: JsonDict): Session {
+        val credentials = executeRequest(null) {
+            authAPI.login(data)
+        }
+
+        return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
+    }
+
     override suspend fun resetPassword(email: String, newPassword: String) {
         val param = RegisterAddThreePidTask.Params(
                 RegisterThreePid.Email(email),
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
index 8f61afe374..28706c7e80 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
@@ -37,7 +37,8 @@ internal interface DirectLoginTask : Task<DirectLoginTask.Params, Session> {
             val homeServerConnectionConfig: HomeServerConnectionConfig,
             val userId: String,
             val password: String,
-            val deviceName: String
+            val deviceName: String,
+            val deviceId: String?
     )
 }
 
@@ -55,7 +56,12 @@ internal class DefaultDirectLoginTask @Inject constructor(
         val authAPI = retrofitFactory.create(client, homeServerUrl)
                 .create(AuthAPI::class.java)
 
-        val loginParams = PasswordLoginParams.userIdentifier(params.userId, params.password, params.deviceName)
+        val loginParams = PasswordLoginParams.userIdentifier(
+                user = params.userId,
+                password = params.password,
+                deviceDisplayName = params.deviceName,
+                deviceId = params.deviceId
+        )
 
         val credentials = try {
             executeRequest(null) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt
index f71c5079b3..9f425eee7f 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt
@@ -38,14 +38,22 @@ data class MXKey(
         /**
          * signature user Id to [deviceid][signature]
          */
-        private val signatures: Map<String, Map<String, String>>
+        private val signatures: Map<String, Map<String, String>>,
+
+        /**
+         * We have to store the original json because it can contain other fields
+         * that we don't support yet but they would be needed to check signatures
+         */
+        private val rawMap: JsonDict
 ) {
 
     /**
      * @return the signed data map
      */
     fun signalableJSONDictionary(): Map<String, Any> {
-        return mapOf("key" to value)
+        return rawMap.filter {
+            it.key != "signatures" && it.key != "unsigned"
+        }
     }
 
     /**
@@ -82,6 +90,7 @@ data class MXKey(
          * <pre>
          *   "signed_curve25519:AAAAFw": {
          *     "key": "IjwIcskng7YjYcn0tS8TUOT2OHHtBSfMpcfIczCgXj4",
+         *     "fallback" : true|false
          *     "signatures": {
          *       "@userId:matrix.org": {
          *         "ed25519:GMJRREOASV": "EUjp6pXzK9u3SDFR\/qLbzpOi3bEREeI6qMnKzXu992HsfuDDZftfJfiUXv9b\/Hqq1og4qM\/vCQJGTHAWMmgkCg"
@@ -107,7 +116,8 @@ data class MXKey(
                                     type = components[0],
                                     keyId = components[1],
                                     value = params["key"] as String,
-                                    signatures = params["signatures"] as Map<String, Map<String, String>>
+                                    signatures = params["signatures"] as Map<String, Map<String, String>>,
+                                    rawMap = params
                             )
                         }
                     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
index e1e297767b..e40db6af67 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
@@ -34,7 +34,7 @@ internal interface SendEventTask : Task<SendEventTask.Params, String> {
 
 internal class DefaultSendEventTask @Inject constructor(
         private val localEchoRepository: LocalEchoRepository,
-        private val encryptEventTask: DefaultEncryptEventTask,
+        private val encryptEventTask: EncryptEventTask,
         private val loadRoomMembersTask: LoadRoomMembersTask,
         private val roomAPI: RoomAPI,
         private val globalErrorReceiver: GlobalErrorReceiver) : SendEventTask {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
index 7fa48c3da1..c4a6ba27d6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
@@ -34,7 +34,7 @@ internal interface SendVerificationMessageTask : Task<SendVerificationMessageTas
 
 internal class DefaultSendVerificationMessageTask @Inject constructor(
         private val localEchoRepository: LocalEchoRepository,
-        private val encryptEventTask: DefaultEncryptEventTask,
+        private val encryptEventTask: EncryptEventTask,
         private val roomAPI: RoomAPI,
         private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
         private val globalErrorReceiver: GlobalErrorReceiver) : SendVerificationMessageTask {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
index 5f80432e82..fa441d4a91 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
@@ -45,17 +45,30 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
 import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
 import org.matrix.android.sdk.internal.di.MoshiProvider
 import org.matrix.android.sdk.internal.query.process
+import org.matrix.android.sdk.internal.util.Normalizer
 import timber.log.Timber
+import javax.inject.Inject
 
-internal object RealmSessionStoreMigration : RealmMigration {
+internal class RealmSessionStoreMigration @Inject constructor(
+        private val normalizer: Normalizer
+) : RealmMigration {
 
-    // SC-specific DB changes on top of Element
-    // 1: added markedUnread field
-    const val SESSION_STORE_SCHEMA_SC_VERSION = 4L
-    const val SESSION_STORE_SCHEMA_SC_VERSION_OFFSET = (1L shl 12)
+    companion object {
+        // SC-specific DB changes on top of Element
+        // 1: added markedUnread field
+        const val SESSION_STORE_SCHEMA_SC_VERSION = 4L
+        const val SESSION_STORE_SCHEMA_SC_VERSION_OFFSET = (1L shl 12)
 
-    const val SESSION_STORE_SCHEMA_VERSION = 18L +
-            SESSION_STORE_SCHEMA_SC_VERSION * SESSION_STORE_SCHEMA_SC_VERSION_OFFSET
+        const val SESSION_STORE_SCHEMA_VERSION = 19L +
+                SESSION_STORE_SCHEMA_SC_VERSION * SESSION_STORE_SCHEMA_SC_VERSION_OFFSET
+    }
+
+    /**
+     * Forces all RealmSessionStoreMigration instances to be equal
+     * Avoids Realm throwing when multiple instances of the migration are set
+     */
+    override fun equals(other: Any?) = other is RealmSessionStoreMigration
+    override fun hashCode() = 1000
 
 
     override fun migrate(realm: DynamicRealm, combinedOldVersion: Long, newVersion: Long) {
@@ -82,6 +95,7 @@ internal object RealmSessionStoreMigration : RealmMigration {
         if (oldVersion <= 15) migrateTo16(realm)
         if (oldVersion <= 16) migrateTo17(realm)
         if (oldVersion <= 17) migrateTo18(realm)
+        if (oldVersion <= 18) migrateTo19(realm)
 
         if (oldScVersion <= 0) migrateToSc1(realm)
         if (oldScVersion <= 1) migrateToSc2(realm)
@@ -410,4 +424,16 @@ internal object RealmSessionStoreMigration : RealmMigration {
         realm.schema.get("RoomMemberSummaryEntity")
                 ?.addRealmObjectField(RoomMemberSummaryEntityFields.USER_PRESENCE_ENTITY.`$`, userPresenceEntity)
     }
+
+    private fun migrateTo19(realm: DynamicRealm) {
+        Timber.d("Step 18 -> 19")
+        realm.schema.get("RoomSummaryEntity")
+                ?.addField(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, String::class.java)
+                ?.transform {
+                    it.getString(RoomSummaryEntityFields.DISPLAY_NAME)?.let { displayName ->
+                        val normalised = normalizer.normalize(displayName)
+                        it.set(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, normalised)
+                    }
+                }
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
index 1771c5b202..04ca26a943 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
@@ -40,6 +40,7 @@ private const val REALM_NAME = "disk_store.realm"
  */
 internal class SessionRealmConfigurationFactory @Inject constructor(
         private val realmKeysUtils: RealmKeysUtils,
+        private val realmSessionStoreMigration: RealmSessionStoreMigration,
         @SessionFilesDirectory val directory: File,
         @SessionId val sessionId: String,
         @UserMd5 val userMd5: String,
@@ -71,7 +72,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
                 .allowWritesOnUiThread(true)
                 .modules(SessionRealmModule())
                 .schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION)
-                .migration(RealmSessionStoreMigration)
+                .migration(realmSessionStoreMigration)
                 .build()
 
         // Try creating a realm instance and if it succeeds we can clear the flag
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
index f7b570917b..97cc8278ea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
@@ -21,13 +21,13 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
 import org.matrix.android.sdk.api.session.room.model.SpaceParentInfo
 import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
+import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
 import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
 import org.matrix.android.sdk.internal.database.model.presence.toUserPresence
-import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker
 import javax.inject.Inject
 
 internal class RoomSummaryMapper @Inject constructor(private val timelineEventMapper: TimelineEventMapper,
-                                                     private val typingUsersTracker: DefaultTypingUsersTracker) {
+                                                     private val typingUsersTracker: TypingUsersTracker) {
 
     fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
         val tags = roomSummaryEntity.tags().map {
@@ -48,7 +48,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
 
         return RoomSummary(
                 roomId = roomSummaryEntity.roomId,
-                displayName = roomSummaryEntity.displayName ?: "",
+                displayName = roomSummaryEntity.displayName() ?: "",
                 name = roomSummaryEntity.name ?: "",
                 topic = roomSummaryEntity.topic ?: "",
                 avatarUrl = roomSummaryEntity.avatarUrl ?: "",
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
index ae1774e7d2..7fa6e76a8e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt
@@ -31,6 +31,7 @@ import org.matrix.android.sdk.api.session.room.model.VersioningState
 import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
+import org.matrix.android.sdk.internal.session.room.membership.RoomName
 import timber.log.Timber
 
 internal open class RoomSummaryEntity(
@@ -40,10 +41,24 @@ internal open class RoomSummaryEntity(
         var children: RealmList<SpaceChildSummaryEntity> = RealmList()
 ) : RealmObject() {
 
-    var displayName: String? = ""
-        set(value) {
-            if (value != field) field = value
+    private var displayName: String? = ""
+
+    fun displayName() = displayName
+
+    fun setDisplayName(roomName: RoomName) {
+        if (roomName.name != displayName) {
+            displayName = roomName.name
+            normalizedDisplayName = roomName.normalizedName
         }
+    }
+
+    /**
+     * Workaround for Realm only supporting Latin-1 character sets when sorting
+     * or filtering by case
+     * See https://github.com/realm/realm-core/issues/777
+     */
+    private var normalizedDisplayName: String? = ""
+
     var avatarUrl: String? = ""
         set(value) {
             if (value != field) field = value
@@ -355,6 +370,7 @@ internal open class RoomSummaryEntity(
                 roomEncryptionTrustLevelStr = value?.name
             }
         }
+
     companion object
 
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt
index 49e155add8..8b78cd0d42 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/DbQualifiers.kt
@@ -37,3 +37,7 @@ internal annotation class CryptoDatabase
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
 internal annotation class IdentityDatabase
+
+@Qualifier
+@Retention(AnnotationRetention.RUNTIME)
+internal annotation class ContentScannerDatabase
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
index fa59b94c17..ad34a4d8a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
@@ -20,6 +20,7 @@ import com.facebook.stetho.okhttp3.StethoInterceptor
 import com.squareup.moshi.Moshi
 import dagger.Module
 import dagger.Provides
+import okhttp3.ConnectionSpec
 import okhttp3.OkHttpClient
 import okhttp3.logging.HttpLoggingInterceptor
 import org.matrix.android.sdk.BuildConfig
@@ -29,6 +30,7 @@ import org.matrix.android.sdk.internal.network.TimeOutInterceptor
 import org.matrix.android.sdk.internal.network.UserAgentInterceptor
 import org.matrix.android.sdk.internal.network.interceptors.CurlLoggingInterceptor
 import org.matrix.android.sdk.internal.network.interceptors.FormattedJsonHttpLogger
+import java.util.Collections
 import java.util.concurrent.TimeUnit
 
 @Module
@@ -66,6 +68,8 @@ internal object NetworkModule {
                              httpLoggingInterceptor: HttpLoggingInterceptor,
                              curlLoggingInterceptor: CurlLoggingInterceptor,
                              apiInterceptor: ApiInterceptor): OkHttpClient {
+        val spec = ConnectionSpec.Builder(matrixConfiguration.connectionSpec).build()
+
         return OkHttpClient.Builder()
                 .connectTimeout(30, TimeUnit.SECONDS)
                 .readTimeout(60, TimeUnit.SECONDS)
@@ -87,6 +91,7 @@ internal object NetworkModule {
                         proxy(it)
                     }
                 }
+                .connectionSpecs(Collections.singletonList(spec))
                 .build()
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt
index 361a306d4f..1ab1042129 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt
@@ -38,6 +38,9 @@ internal object NetworkConstants {
     // Integration
     const val URI_INTEGRATION_MANAGER_PATH = "_matrix/integrations/v1/"
 
+    // Content scanner
+    const val URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE = "_matrix/media_proxy/unstable/"
+
     // Federation
     const val URI_FEDERATION_PATH = "_matrix/federation/v1/"
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt
index 92c7f3f236..d8bdc5fc2b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt
@@ -177,15 +177,13 @@ internal object CertUtil {
 
             val trustPinned = arrayOf<TrustManager>(PinnedTrustManagerProvider.provide(hsConfig.allowedFingerprints, defaultTrustManager))
 
-            val sslSocketFactory: SSLSocketFactory
-
-            if (hsConfig.forceUsageTlsVersions && hsConfig.tlsVersions != null) {
+            val sslSocketFactory = if (hsConfig.forceUsageTlsVersions && !hsConfig.tlsVersions.isNullOrEmpty()) {
                 // Force usage of accepted Tls Versions for Android < 20
-                sslSocketFactory = TLSSocketFactory(trustPinned, hsConfig.tlsVersions)
+                TLSSocketFactory(trustPinned, hsConfig.tlsVersions)
             } else {
                 val sslContext = SSLContext.getInstance("TLS")
                 sslContext.init(null, trustPinned, java.security.SecureRandom())
-                sslSocketFactory = sslContext.socketFactory
+                sslContext.socketFactory
             }
 
             return PinnedSSLSocketFactory(sslSocketFactory, defaultTrustManager!!)
@@ -237,14 +235,14 @@ internal object CertUtil {
      * @return a list of accepted TLS specifications.
      */
     fun newConnectionSpecs(hsConfig: HomeServerConnectionConfig): List<ConnectionSpec> {
-        val builder = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
+        val builder = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
         val tlsVersions = hsConfig.tlsVersions
-        if (null != tlsVersions && tlsVersions.isNotEmpty()) {
+        if (!tlsVersions.isNullOrEmpty()) {
             builder.tlsVersions(*tlsVersions.toTypedArray())
         }
 
         val tlsCipherSuites = hsConfig.tlsCipherSuites
-        if (null != tlsCipherSuites && tlsCipherSuites.isNotEmpty()) {
+        if (!tlsCipherSuites.isNullOrEmpty()) {
             builder.cipherSuites(*tlsCipherSuites.toTypedArray())
         }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
index fd33682231..b42bf2b8c7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
@@ -20,24 +20,41 @@ import io.realm.Case
 import io.realm.RealmObject
 import io.realm.RealmQuery
 import org.matrix.android.sdk.api.query.QueryStringValue
-import timber.log.Timber
+import org.matrix.android.sdk.api.query.QueryStringValue.ContentQueryStringValue
+import org.matrix.android.sdk.internal.util.Normalizer
+import javax.inject.Inject
 
-fun <T : RealmObject> RealmQuery<T>.process(field: String, queryStringValue: QueryStringValue): RealmQuery<T> {
-    when (queryStringValue) {
-        is QueryStringValue.NoCondition -> Timber.v("No condition to process")
-        is QueryStringValue.IsNotNull   -> isNotNull(field)
-        is QueryStringValue.IsNull      -> isNull(field)
-        is QueryStringValue.IsEmpty     -> isEmpty(field)
-        is QueryStringValue.IsNotEmpty  -> isNotEmpty(field)
-        is QueryStringValue.Equals      -> equalTo(field, queryStringValue.string, queryStringValue.case.toRealmCase())
-        is QueryStringValue.Contains    -> contains(field, queryStringValue.string, queryStringValue.case.toRealmCase())
+class QueryStringValueProcessor @Inject constructor(
+        private val normalizer: Normalizer
+) {
+
+    fun <T : RealmObject> RealmQuery<T>.process(field: String, queryStringValue: QueryStringValue): RealmQuery<T> {
+        return when (queryStringValue) {
+            is QueryStringValue.NoCondition -> this
+            is QueryStringValue.IsNotNull   -> isNotNull(field)
+            is QueryStringValue.IsNull      -> isNull(field)
+            is QueryStringValue.IsEmpty     -> isEmpty(field)
+            is QueryStringValue.IsNotEmpty  -> isNotEmpty(field)
+            is ContentQueryStringValue      -> when (queryStringValue) {
+                is QueryStringValue.Equals   -> equalTo(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase())
+                is QueryStringValue.Contains -> contains(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase())
+            }
+        }
+    }
+
+    private fun ContentQueryStringValue.toRealmValue(): String {
+        return when (case) {
+            QueryStringValue.Case.NORMALIZED  -> normalizer.normalize(string)
+            QueryStringValue.Case.SENSITIVE,
+            QueryStringValue.Case.INSENSITIVE -> string
+        }
     }
-    return this
 }
 
 private fun QueryStringValue.Case.toRealmCase(): Case {
     return when (this) {
         QueryStringValue.Case.INSENSITIVE -> Case.INSENSITIVE
-        QueryStringValue.Case.SENSITIVE   -> Case.SENSITIVE
+        QueryStringValue.Case.SENSITIVE,
+        QueryStringValue.Case.NORMALIZED  -> Case.SENSITIVE
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
index 46c5967876..14dfc097cf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
@@ -23,8 +23,10 @@ import androidx.core.content.FileProvider
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.completeWith
 import kotlinx.coroutines.withContext
+import okhttp3.MediaType.Companion.toMediaType
 import okhttp3.OkHttpClient
 import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
@@ -118,12 +120,24 @@ internal class DefaultFileService @Inject constructor(
                 val cachedFiles = getFiles(url, fileName, mimeType, elementToDecrypt != null)
 
                 if (!cachedFiles.file.exists()) {
-                    val resolvedUrl = contentUrlResolver.resolveFullSize(url) ?: throw IllegalArgumentException("url is null")
+                    val resolvedUrl = contentUrlResolver.resolveForDownload(url, elementToDecrypt) ?: throw IllegalArgumentException("url is null")
 
-                    val request = Request.Builder()
-                            .url(resolvedUrl)
-                            .header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
-                            .build()
+                    val request = when (resolvedUrl) {
+                        is ContentUrlResolver.ResolvedMethod.GET -> {
+                            Request.Builder()
+                                    .url(resolvedUrl.url)
+                                    .header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
+                                    .build()
+                        }
+
+                        is ContentUrlResolver.ResolvedMethod.POST -> {
+                            Request.Builder()
+                                    .url(resolvedUrl.url)
+                                    .header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
+                                    .post(resolvedUrl.jsonBody.toRequestBody("application/json".toMediaType()))
+                                    .build()
+                        }
+                    }
 
                     val response = try {
                         okHttpClient.newCall(request).execute()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
index 6a6bce5ce2..c07ff48cf4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
@@ -35,12 +35,14 @@ import org.matrix.android.sdk.api.session.cache.CacheService
 import org.matrix.android.sdk.api.session.call.CallSignalingService
 import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
 import org.matrix.android.sdk.api.session.crypto.CryptoService
 import org.matrix.android.sdk.api.session.events.EventService
 import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
 import org.matrix.android.sdk.api.session.file.FileService
 import org.matrix.android.sdk.api.session.group.GroupService
 import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
+import org.matrix.android.sdk.api.session.identity.IdentityService
 import org.matrix.android.sdk.api.session.initsync.SyncStatusService
 import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
 import org.matrix.android.sdk.api.session.media.MediaService
@@ -72,7 +74,6 @@ import org.matrix.android.sdk.internal.di.SessionId
 import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
 import org.matrix.android.sdk.internal.di.WorkManagerProvider
 import org.matrix.android.sdk.internal.network.GlobalErrorHandler
-import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
 import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
 import org.matrix.android.sdk.internal.session.sync.job.SyncThread
 import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
@@ -124,7 +125,8 @@ internal class DefaultSession @Inject constructor(
         private val _sharedSecretStorageService: Lazy<SharedSecretStorageService>,
         private val accountService: Lazy<AccountService>,
         private val eventService: Lazy<EventService>,
-        private val defaultIdentityService: DefaultIdentityService,
+        private val contentScannerService: Lazy<ContentScannerService>,
+        private val identityService: IdentityService,
         private val integrationManagerService: IntegrationManagerService,
         private val thirdPartyService: Lazy<ThirdPartyService>,
         private val callSignalingService: Lazy<CallSignalingService>,
@@ -174,8 +176,8 @@ internal class DefaultSession @Inject constructor(
             lifecycleObservers.forEach {
                 it.onSessionStarted(this)
             }
-            sessionListeners.dispatch { _, listener ->
-                listener.onSessionStarted(this)
+            dispatchTo(sessionListeners) { session, listener ->
+                listener.onSessionStarted(session)
             }
         }
     }
@@ -217,8 +219,8 @@ internal class DefaultSession @Inject constructor(
         // timelineEventDecryptor.destroy()
         uiHandler.post {
             lifecycleObservers.forEach { it.onSessionStopped(this) }
-            sessionListeners.dispatch { _, listener ->
-                listener.onSessionStopped(this)
+            dispatchTo(sessionListeners) { session, listener ->
+                listener.onSessionStopped(session)
             }
         }
         cryptoService.get().close()
@@ -249,8 +251,8 @@ internal class DefaultSession @Inject constructor(
             lifecycleObservers.forEach {
                 it.onClearCache(this)
             }
-            sessionListeners.dispatch { _, listener ->
-                listener.onClearCache(this)
+            dispatchTo(sessionListeners) { session, listener ->
+                listener.onClearCache(session)
             }
         }
         withContext(NonCancellable) {
@@ -260,8 +262,8 @@ internal class DefaultSession @Inject constructor(
     }
 
     override fun onGlobalError(globalError: GlobalError) {
-        sessionListeners.dispatch { _, listener ->
-            listener.onGlobalError(this, globalError)
+        dispatchTo(sessionListeners) { session, listener ->
+            listener.onGlobalError(session, globalError)
         }
     }
 
@@ -275,7 +277,9 @@ internal class DefaultSession @Inject constructor(
 
     override fun cryptoService(): CryptoService = cryptoService.get()
 
-    override fun identityService() = defaultIdentityService
+    override fun contentScannerService(): ContentScannerService = contentScannerService.get()
+
+    override fun identityService() = identityService
 
     override fun fileService(): FileService = defaultFileService.get()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
index bc8a707530..76e5d84e56 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
@@ -36,6 +36,7 @@ import org.matrix.android.sdk.internal.session.cache.CacheModule
 import org.matrix.android.sdk.internal.session.call.CallModule
 import org.matrix.android.sdk.internal.session.content.ContentModule
 import org.matrix.android.sdk.internal.session.content.UploadContentWorker
+import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerModule
 import org.matrix.android.sdk.internal.session.filter.FilterModule
 import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
 import org.matrix.android.sdk.internal.session.group.GroupModule
@@ -94,6 +95,7 @@ import org.matrix.android.sdk.internal.util.system.SystemModule
             AccountModule::class,
             FederationModule::class,
             CallModule::class,
+            ContentScannerModule::class,
             SearchModule::class,
             ThirdPartyModule::class,
             SpaceModule::class,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt
index d5c661b1e4..756b9cef83 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionListeners.kt
@@ -18,15 +18,11 @@ package org.matrix.android.sdk.internal.session
 
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.di.SessionId
 import timber.log.Timber
 import javax.inject.Inject
 
 @SessionScope
-internal class SessionListeners @Inject constructor(
-        @SessionId private val sessionId: String,
-        private val sessionManager: SessionManager) {
+internal class SessionListeners @Inject constructor() {
 
     private val listeners = mutableSetOf<Session.Listener>()
 
@@ -42,18 +38,19 @@ internal class SessionListeners @Inject constructor(
         }
     }
 
-    fun dispatch(block: (Session, Session.Listener) -> Unit) {
+    fun dispatch(session: Session, block: (Session, Session.Listener) -> Unit) {
         synchronized(listeners) {
-            val session = getSession() ?: return Unit.also {
-                Timber.w("You don't have any attached session")
-            }
             listeners.forEach {
                 tryOrNull { block(session, it) }
             }
         }
     }
-
-    private fun getSession(): Session? {
-        return sessionManager.getSessionComponent(sessionId)?.session()
-    }
+}
+
+internal fun Session?.dispatchTo(sessionListeners: SessionListeners, block: (Session, Session.Listener) -> Unit) {
+    if (this == null) {
+        Timber.w("You don't have any attached session")
+        return
+    }
+    sessionListeners.dispatch(this, block)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
index dc59277f64..ebc2176a13 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
@@ -163,6 +163,7 @@ internal abstract class SessionModule {
         @JvmStatic
         @Provides
         @SessionFilesDirectory
+        @SessionScope
         fun providesFilesDir(@UserMd5 userMd5: String,
                              @SessionId sessionId: String,
                              context: Context): File {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
index 1a8e80ab68..752856b931 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
@@ -44,7 +44,7 @@ internal class DefaultDeactivateAccountTask @Inject constructor(
 
     override suspend fun execute(params: DeactivateAccountTask.Params) {
         val deactivateAccountParams = DeactivateAccountParams.create(params.userAuthParam, params.eraseAllData)
-
+        cleanupSession.stopActiveTasks()
         val canCleanup = try {
             executeRequest(globalErrorReceiver) {
                 accountAPI.deactivate(deactivateAccountParams)
@@ -71,7 +71,7 @@ internal class DefaultDeactivateAccountTask @Inject constructor(
             runCatching { identityDisconnectTask.execute(Unit) }
                     .onFailure { Timber.w(it, "Unable to disconnect identity server") }
 
-            cleanupSession.handle()
+            cleanupSession.cleanup()
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cleanup/CleanupSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cleanup/CleanupSession.kt
index e8d3eb1a78..c42141a0aa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cleanup/CleanupSession.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/cleanup/CleanupSession.kt
@@ -50,20 +50,26 @@ internal class CleanupSession @Inject constructor(
         @CryptoDatabase private val realmCryptoConfiguration: RealmConfiguration,
         @UserMd5 private val userMd5: String
 ) {
-    suspend fun handle() {
+
+    fun stopActiveTasks() {
+        Timber.d("Cleanup: cancel pending works...")
+        workManagerProvider.cancelAllWorks()
+
+        Timber.d("Cleanup: stop session...")
+        sessionManager.stopSession(sessionId)
+    }
+
+    suspend fun cleanup() {
         val sessionRealmCount = Realm.getGlobalInstanceCount(realmSessionConfiguration)
         val cryptoRealmCount = Realm.getGlobalInstanceCount(realmCryptoConfiguration)
         Timber.d("Realm instance ($sessionRealmCount - $cryptoRealmCount)")
 
-        Timber.d("Cleanup: delete session params...")
-        sessionParamsStore.delete(sessionId)
-
-        Timber.d("Cleanup: cancel pending works...")
-        workManagerProvider.cancelAllWorks()
-
         Timber.d("Cleanup: release session...")
         sessionManager.releaseSession(sessionId)
 
+        Timber.d("Cleanup: delete session params...")
+        sessionParamsStore.delete(sessionId)
+
         Timber.d("Cleanup: clear session data...")
         clearSessionDataTask.execute(Unit)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt
index 5c8cf99dc6..660ab8726f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt
@@ -16,20 +16,45 @@
 
 package org.matrix.android.sdk.internal.session.content
 
-import org.matrix.android.sdk.api.MatrixUrls
 import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
+import org.matrix.android.sdk.api.MatrixUrls.removeMxcPrefix
 import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
 import org.matrix.android.sdk.internal.network.NetworkConstants
+import org.matrix.android.sdk.internal.session.contentscanner.ScanEncryptorUtils
+import org.matrix.android.sdk.internal.session.contentscanner.model.toJson
 import org.matrix.android.sdk.internal.util.ensureTrailingSlash
 import javax.inject.Inject
 
-internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {
+internal class DefaultContentUrlResolver @Inject constructor(
+        homeServerConnectionConfig: HomeServerConnectionConfig,
+        private val scannerService: ContentScannerService
+) : ContentUrlResolver {
 
     private val baseUrl = homeServerConnectionConfig.homeServerUriBase.toString().ensureTrailingSlash()
 
     override val uploadUrl = baseUrl + NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "upload"
 
+    override fun resolveForDownload(contentUrl: String?, elementToDecrypt: ElementToDecrypt?): ContentUrlResolver.ResolvedMethod? {
+        return if (scannerService.isScannerEnabled() && elementToDecrypt != null) {
+            val baseUrl = scannerService.getContentScannerServer()
+            val sep = if (baseUrl?.endsWith("/") == true) "" else "/"
+
+            val url = baseUrl + sep + NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE + "download_encrypted"
+
+            ContentUrlResolver.ResolvedMethod.POST(
+                    url = url,
+                    jsonBody = ScanEncryptorUtils
+                            .getDownloadBodyAndEncryptIfNeeded(scannerService.serverPublicKey, contentUrl ?: "", elementToDecrypt)
+                            .toJson()
+            )
+        } else {
+            resolveFullSize(contentUrl)?.let { ContentUrlResolver.ResolvedMethod.GET(it) }
+        }
+    }
+
     override fun resolveFullSize(contentUrl: String?): String? {
         return contentUrl
                 // do not allow non-mxc content URLs
@@ -37,7 +62,7 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
                 ?.let {
                     resolve(
                             contentUrl = it,
-                            prefix = NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "download/"
+                            toThumbnail = false
                     )
                 }
     }
@@ -49,16 +74,27 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
                 ?.let {
                     resolve(
                             contentUrl = it,
-                            prefix = NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0 + "thumbnail/",
+                            toThumbnail = true,
                             params = "?width=$width&height=$height&method=${method.value}"
                     )
                 }
     }
 
     private fun resolve(contentUrl: String,
-                        prefix: String,
-                        params: String = ""): String? {
-        var serverAndMediaId = contentUrl.removePrefix(MatrixUrls.MATRIX_CONTENT_URI_SCHEME)
+                        toThumbnail: Boolean,
+                        params: String = ""): String {
+        var serverAndMediaId = contentUrl.removeMxcPrefix()
+
+        val apiPath = if (scannerService.isScannerEnabled()) {
+            NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE
+        } else {
+            NetworkConstants.URI_API_MEDIA_PREFIX_PATH_R0
+        }
+        val prefix = if (toThumbnail) {
+            apiPath + "thumbnail/"
+        } else {
+            apiPath + "download/"
+        }
         val fragmentOffset = serverAndMediaId.indexOf("#")
         var fragment = ""
         if (fragmentOffset >= 0) {
@@ -66,6 +102,11 @@ internal class DefaultContentUrlResolver @Inject constructor(homeServerConnectio
             serverAndMediaId = serverAndMediaId.substring(0, fragmentOffset)
         }
 
-        return baseUrl + prefix + serverAndMediaId + params + fragment
+        val resolvedUrl = if (scannerService.isScannerEnabled()) {
+            scannerService.getContentScannerServer()!!.ensureTrailingSlash()
+        } else {
+            baseUrl
+        }
+        return resolvedUrl + prefix + serverAndMediaId + params + fragment
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
index bdebb0addf..1b0ccbb489 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
@@ -35,12 +35,12 @@ import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
 import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
+import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
 import org.matrix.android.sdk.internal.di.Authenticated
 import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
 import org.matrix.android.sdk.internal.network.ProgressRequestBody
 import org.matrix.android.sdk.internal.network.awaitResponse
 import org.matrix.android.sdk.internal.network.toFailure
-import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
 import org.matrix.android.sdk.internal.util.TemporaryFileCreator
 import java.io.File
 import java.io.FileNotFoundException
@@ -50,7 +50,7 @@ import javax.inject.Inject
 internal class FileUploader @Inject constructor(
         @Authenticated private val okHttpClient: OkHttpClient,
         private val globalErrorReceiver: GlobalErrorReceiver,
-        private val homeServerCapabilitiesService: DefaultHomeServerCapabilitiesService,
+        private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
         private val context: Context,
         private val temporaryFileCreator: TemporaryFileCreator,
         contentUrlResolver: ContentUrlResolver,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
index f1b60f5ecf..567fec962a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
@@ -217,8 +217,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
                                                 .also { filesToDelete.add(it) }
                                     }
                                     VideoCompressionResult.CompressionNotNeeded,
-                                    VideoCompressionResult.CompressionCancelled,
+                                    VideoCompressionResult.CompressionCancelled -> {
+                                        workingFile
+                                    }
                                     is VideoCompressionResult.CompressionFailed -> {
+                                        Timber.e(videoCompressionResult.failure, "Video compression failed")
                                         workingFile
                                     }
                                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
index e119a2234c..a43f8abf33 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
@@ -44,7 +44,7 @@ internal class VideoCompressor @Inject constructor(
         var result: Int = -1
         var failure: Throwable? = null
         Transcoder.into(destinationFile.path)
-                .addDataSource(object: FilePathDataSource(videoFile.path) {
+                .addDataSource(object : FilePathDataSource(videoFile.path) {
                     // https://github.com/natario1/Transcoder/issues/154
                     @Suppress("SENSELESS_COMPARISON") // Source is annotated as @NonNull, but can actually be null...
                     override fun isInitialized(): Boolean {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerApi.kt
new file mode 100644
index 0000000000..46f1705806
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerApi.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner
+
+import okhttp3.ResponseBody
+import org.matrix.android.sdk.internal.network.NetworkConstants
+import org.matrix.android.sdk.internal.session.contentscanner.model.DownloadBody
+import org.matrix.android.sdk.internal.session.contentscanner.model.ScanResponse
+import org.matrix.android.sdk.internal.session.contentscanner.model.ServerPublicKeyResponse
+import retrofit2.http.Body
+import retrofit2.http.GET
+import retrofit2.http.POST
+import retrofit2.http.Path
+
+/**
+ * https://github.com/matrix-org/matrix-content-scanner
+ */
+internal interface ContentScannerApi {
+
+    @POST(NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE + "download_encrypted")
+    suspend fun downloadEncrypted(@Body info: DownloadBody): ResponseBody
+
+    @POST(NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE + "scan_encrypted")
+    suspend fun scanFile(@Body info: DownloadBody): ScanResponse
+
+    @GET(NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE + "public_key")
+    suspend fun getServerPublicKey(): ServerPublicKeyResponse
+
+    @GET(NetworkConstants.URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE + "scan/{domain}/{mediaId}")
+    suspend fun scanMedia(@Path(value = "domain") domain: String, @Path(value = "mediaId") mediaId: String): ScanResponse
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerApiProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerApiProvider.kt
new file mode 100644
index 0000000000..d8548bb238
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerApiProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner
+
+import org.matrix.android.sdk.internal.session.SessionScope
+import javax.inject.Inject
+
+@SessionScope
+internal class ContentScannerApiProvider @Inject constructor() {
+    var contentScannerApi: ContentScannerApi? = null
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt
new file mode 100644
index 0000000000..7ea74225cd
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner
+
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import io.realm.RealmConfiguration
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
+import org.matrix.android.sdk.internal.database.RealmKeysUtils
+import org.matrix.android.sdk.internal.di.ContentScannerDatabase
+import org.matrix.android.sdk.internal.di.SessionFilesDirectory
+import org.matrix.android.sdk.internal.di.UserMd5
+import org.matrix.android.sdk.internal.session.SessionModule
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.contentscanner.data.ContentScannerStore
+import org.matrix.android.sdk.internal.session.contentscanner.db.ContentScannerRealmModule
+import org.matrix.android.sdk.internal.session.contentscanner.db.RealmContentScannerStore
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.DefaultDownloadEncryptedTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.DefaultGetServerPublicKeyTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.DefaultScanEncryptedTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.DefaultScanMediaTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.DownloadEncryptedTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.GetServerPublicKeyTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.ScanEncryptedTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.ScanMediaTask
+import java.io.File
+
+@Module
+internal abstract class ContentScannerModule {
+    @Module
+    companion object {
+
+        @JvmStatic
+        @Provides
+        @ContentScannerDatabase
+        @SessionScope
+        fun providesContentScannerRealmConfiguration(realmKeysUtils: RealmKeysUtils,
+                                                     @SessionFilesDirectory directory: File,
+                                                     @UserMd5 userMd5: String): RealmConfiguration {
+            return RealmConfiguration.Builder()
+                    .directory(directory)
+                    .name("matrix-sdk-content-scanning.realm")
+                    .apply {
+                        realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
+                    }
+                    .allowWritesOnUiThread(true)
+                    .modules(ContentScannerRealmModule())
+                    .build()
+        }
+    }
+
+    @Binds
+    abstract fun bindContentScannerService(service: DisabledContentScannerService): ContentScannerService
+
+    @Binds
+    abstract fun bindContentScannerStore(store: RealmContentScannerStore): ContentScannerStore
+
+    @Binds
+    abstract fun bindDownloadEncryptedTask(task: DefaultDownloadEncryptedTask): DownloadEncryptedTask
+
+    @Binds
+    abstract fun bindGetServerPublicKeyTask(task: DefaultGetServerPublicKeyTask): GetServerPublicKeyTask
+
+    @Binds
+    abstract fun bindScanMediaTask(task: DefaultScanMediaTask): ScanMediaTask
+
+    @Binds
+    abstract fun bindScanEncryptedTask(task: DefaultScanEncryptedTask): ScanEncryptedTask
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/DefaultContentScannerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/DefaultContentScannerService.kt
new file mode 100644
index 0000000000..4ecb337603
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/DefaultContentScannerService.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner
+
+import androidx.lifecycle.LiveData
+import dagger.Lazy
+import kotlinx.coroutines.launch
+import okhttp3.OkHttpClient
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
+import org.matrix.android.sdk.api.session.contentscanner.ScanState
+import org.matrix.android.sdk.api.session.contentscanner.ScanStatusInfo
+import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+import org.matrix.android.sdk.internal.di.Unauthenticated
+import org.matrix.android.sdk.internal.network.RetrofitFactory
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.contentscanner.data.ContentScannerStore
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.GetServerPublicKeyTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.ScanEncryptedTask
+import org.matrix.android.sdk.internal.session.contentscanner.tasks.ScanMediaTask
+import org.matrix.android.sdk.internal.task.TaskExecutor
+import timber.log.Timber
+import javax.inject.Inject
+
+@SessionScope
+internal class DefaultContentScannerService @Inject constructor(
+        private val retrofitFactory: RetrofitFactory,
+        @Unauthenticated
+        private val okHttpClient: Lazy<OkHttpClient>,
+        private val contentScannerApiProvider: ContentScannerApiProvider,
+        private val contentScannerStore: ContentScannerStore,
+        private val getServerPublicKeyTask: GetServerPublicKeyTask,
+        private val scanEncryptedTask: ScanEncryptedTask,
+        private val scanMediaTask: ScanMediaTask,
+        private val taskExecutor: TaskExecutor
+) : ContentScannerService {
+
+    // Cache public key in memory
+    override var serverPublicKey: String? = null
+        private set
+
+    override fun getContentScannerServer(): String? {
+        return contentScannerStore.getScannerUrl()
+    }
+
+    override suspend fun getServerPublicKey(forceDownload: Boolean): String? {
+        val api = contentScannerApiProvider.contentScannerApi ?: throw IllegalArgumentException("No content scanner define")
+
+        if (!forceDownload && serverPublicKey != null) {
+            return serverPublicKey
+        }
+
+        return getServerPublicKeyTask.execute(GetServerPublicKeyTask.Params(api)).also {
+            serverPublicKey = it
+        }
+    }
+
+    override suspend fun getScanResultForAttachment(mxcUrl: String, fileInfo: ElementToDecrypt?): ScanStatusInfo {
+        val result = if (fileInfo != null) {
+            scanEncryptedTask.execute(ScanEncryptedTask.Params(
+                    mxcUrl = mxcUrl,
+                    publicServerKey = getServerPublicKey(false),
+                    encryptedInfo = fileInfo
+            ))
+        } else {
+            scanMediaTask.execute(ScanMediaTask.Params(mxcUrl))
+        }
+
+        return ScanStatusInfo(
+                state = if (result.clean) ScanState.TRUSTED else ScanState.INFECTED,
+                humanReadableMessage = result.info,
+                scanDateTimestamp = System.currentTimeMillis()
+        )
+    }
+
+    override fun setScannerUrl(url: String?) = contentScannerStore.setScannerUrl(url).also {
+        if (url == null) {
+            contentScannerApiProvider.contentScannerApi = null
+            serverPublicKey = null
+        } else {
+            val api = retrofitFactory
+                    .create(okHttpClient, url)
+                    .create(ContentScannerApi::class.java)
+            contentScannerApiProvider.contentScannerApi = api
+
+            taskExecutor.executorScope.launch {
+                try {
+                    getServerPublicKey(true)
+                } catch (failure: Throwable) {
+                    Timber.e("Failed to get public server api")
+                }
+            }
+        }
+    }
+
+    override fun enableScanner(enabled: Boolean) = contentScannerStore.enableScanner(enabled)
+
+    override fun isScannerEnabled(): Boolean = contentScannerStore.isScanEnabled()
+
+    override fun getCachedScanResultForFile(mxcUrl: String): ScanStatusInfo? {
+        return contentScannerStore.getScanResult(mxcUrl)
+    }
+
+    override fun getLiveStatusForFile(mxcUrl: String, fetchIfNeeded: Boolean, fileInfo: ElementToDecrypt?): LiveData<Optional<ScanStatusInfo>> {
+        val data = contentScannerStore.getLiveScanResult(mxcUrl)
+        if (fetchIfNeeded && !contentScannerStore.isScanResultKnownOrInProgress(mxcUrl, getContentScannerServer())) {
+            taskExecutor.executorScope.launch {
+                try {
+                    getScanResultForAttachment(mxcUrl, fileInfo)
+                } catch (failure: Throwable) {
+                    Timber.e("Failed to get file status : ${failure.localizedMessage}")
+                }
+            }
+        }
+        return data
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/DisabledContentScannerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/DisabledContentScannerService.kt
new file mode 100644
index 0000000000..9087c71566
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/DisabledContentScannerService.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import org.matrix.android.sdk.api.session.contentscanner.ContentScannerService
+import org.matrix.android.sdk.api.session.contentscanner.ScanStatusInfo
+import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+import org.matrix.android.sdk.internal.session.SessionScope
+import javax.inject.Inject
+
+/**
+ * Created to by-pass ProfileTask execution in LoginWizard.
+ */
+@SessionScope
+internal class DisabledContentScannerService @Inject constructor() : ContentScannerService {
+
+    override val serverPublicKey: String?
+        get() = null
+
+    override fun getContentScannerServer(): String? {
+        return null
+    }
+
+    override suspend fun getServerPublicKey(forceDownload: Boolean): String? {
+        return null
+    }
+
+    override suspend fun getScanResultForAttachment(mxcUrl: String, fileInfo: ElementToDecrypt?): ScanStatusInfo {
+        TODO("Not yet implemented")
+    }
+
+    override fun setScannerUrl(url: String?) {
+    }
+
+    override fun enableScanner(enabled: Boolean) {
+    }
+
+    override fun isScannerEnabled(): Boolean {
+        return false
+    }
+
+    override fun getLiveStatusForFile(mxcUrl: String, fetchIfNeeded: Boolean, fileInfo: ElementToDecrypt?): LiveData<Optional<ScanStatusInfo>> {
+        return MutableLiveData()
+    }
+
+    override fun getCachedScanResultForFile(mxcUrl: String): ScanStatusInfo? {
+        return null
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt
new file mode 100644
index 0000000000..8fc84a487e
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ScanEncryptorUtils.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner
+
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
+import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey
+import org.matrix.android.sdk.internal.crypto.tools.withOlmEncryption
+import org.matrix.android.sdk.internal.session.contentscanner.model.DownloadBody
+import org.matrix.android.sdk.internal.session.contentscanner.model.EncryptedBody
+import org.matrix.android.sdk.internal.session.contentscanner.model.toCanonicalJson
+
+internal object ScanEncryptorUtils {
+
+    fun getDownloadBodyAndEncryptIfNeeded(publicServerKey: String?, mxcUrl: String, elementToDecrypt: ElementToDecrypt): DownloadBody {
+        // TODO, upstream refactoring changed the object model here...
+        // it's bad we have to recreate and use hardcoded values
+        val encryptedInfo = EncryptedFileInfo(
+                url = mxcUrl,
+                iv = elementToDecrypt.iv,
+                hashes = mapOf("sha256" to elementToDecrypt.sha256),
+                key = EncryptedFileKey(
+                        k = elementToDecrypt.k,
+                        alg = "A256CTR",
+                        keyOps = listOf("encrypt", "decrypt"),
+                        kty = "oct",
+                        ext = true
+                ),
+                v = "v2"
+        )
+        return if (publicServerKey != null) {
+            // We should encrypt
+            withOlmEncryption { olm ->
+                olm.setRecipientKey(publicServerKey)
+
+                val olmResult = olm.encrypt(DownloadBody(encryptedInfo).toCanonicalJson())
+                DownloadBody(
+                        encryptedBody = EncryptedBody(
+                                cipherText = olmResult.mCipherText,
+                                ephemeral = olmResult.mEphemeralKey,
+                                mac = olmResult.mMac
+                        )
+                )
+            }
+        } else {
+            DownloadBody(encryptedInfo)
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/data/ContentScannerStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/data/ContentScannerStore.kt
new file mode 100644
index 0000000000..5cfe851a5c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/data/ContentScannerStore.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.data
+
+import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.session.contentscanner.ScanState
+import org.matrix.android.sdk.api.session.contentscanner.ScanStatusInfo
+import org.matrix.android.sdk.api.util.Optional
+
+internal interface ContentScannerStore {
+
+    fun getScannerUrl(): String?
+
+    fun setScannerUrl(url: String?)
+
+    fun enableScanner(enabled: Boolean)
+
+    fun isScanEnabled(): Boolean
+
+    fun getScanResult(mxcUrl: String): ScanStatusInfo?
+    fun getLiveScanResult(mxcUrl: String): LiveData<Optional<ScanStatusInfo>>
+    fun isScanResultKnownOrInProgress(mxcUrl: String, scannerUrl: String?): Boolean
+
+    fun updateStateForContent(mxcUrl: String, state: ScanState, scannerUrl: String?)
+    fun updateScanResultForContent(mxcUrl: String, scannerUrl: String?, state: ScanState, humanReadable: String)
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScanResultEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScanResultEntity.kt
new file mode 100644
index 0000000000..0ffff441f8
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScanResultEntity.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.db
+
+import io.realm.RealmObject
+import io.realm.annotations.Index
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.contentscanner.ScanState
+import org.matrix.android.sdk.api.session.contentscanner.ScanStatusInfo
+
+internal open class ContentScanResultEntity(
+        @Index
+        var mediaUrl: String? = null,
+        var scanStatusString: String? = null,
+        var humanReadableMessage: String? = null,
+        var scanDateTimestamp: Long? = null,
+        var scannerUrl: String? = null
+) : RealmObject() {
+
+    var scanResult: ScanState
+        get() {
+            return scanStatusString
+                    ?.let {
+                        tryOrNull { ScanState.valueOf(it) }
+                    }
+                    ?: ScanState.UNKNOWN
+        }
+        set(result) {
+            scanStatusString = result.name
+        }
+
+    fun toModel(): ScanStatusInfo {
+        return ScanStatusInfo(
+                state = this.scanResult,
+                humanReadableMessage = humanReadableMessage,
+                scanDateTimestamp = scanDateTimestamp
+        )
+    }
+
+    companion object
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt
new file mode 100644
index 0000000000..b47be235c6
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.db
+
+import io.realm.Realm
+import io.realm.kotlin.createObject
+import io.realm.kotlin.where
+
+internal fun ContentScanResultEntity.Companion.get(realm: Realm, attachmentUrl: String, contentScannerUrl: String?): ContentScanResultEntity? {
+    return realm.where<ContentScanResultEntity>()
+            .equalTo(ContentScanResultEntityFields.MEDIA_URL, attachmentUrl)
+            .apply {
+                contentScannerUrl?.let {
+                    equalTo(ContentScanResultEntityFields.SCANNER_URL, it)
+                }
+            }
+            .findFirst()
+}
+
+internal fun ContentScanResultEntity.Companion.getOrCreate(realm: Realm, attachmentUrl: String, contentScannerUrl: String?): ContentScanResultEntity {
+    return ContentScanResultEntity.get(realm, attachmentUrl, contentScannerUrl)
+            ?: realm.createObject<ContentScanResultEntity>().also {
+                it.mediaUrl = attachmentUrl
+                it.scanDateTimestamp = System.currentTimeMillis()
+                it.scannerUrl = contentScannerUrl
+            }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerInfoEntity.kt
similarity index 64%
rename from vector/src/main/java/im/vector/app/features/home/room/list/RoomListModule.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerInfoEntity.kt
index 5dcef663e6..d1910de36a 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerInfoEntity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 New Vector Ltd
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.home.room.list
+package org.matrix.android.sdk.internal.session.contentscanner.db
 
-import dagger.Binds
-import dagger.Module
+import io.realm.RealmObject
 
-@Module
-abstract class RoomListModule {
+internal open class ContentScannerInfoEntity(
+        var serverUrl: String? = null,
+        var enabled: Boolean? = null
+) : RealmObject() {
 
-    @Binds
-    abstract fun providesRoomListViewModelFactory(factory: RoomListViewModelFactory): RoomListViewModel.Factory
+    companion object
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt
new file mode 100644
index 0000000000..bb53140ad9
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.db
+
+import io.realm.annotations.RealmModule
+
+/**
+ * Realm module for content scanner classes
+ */
+@RealmModule(library = true,
+        classes = [
+            ContentScannerInfoEntity::class,
+            ContentScanResultEntity::class
+        ])
+internal class ContentScannerRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt
new file mode 100644
index 0000000000..947a66c8b9
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.db
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.Transformations
+import com.zhuinden.monarchy.Monarchy
+import io.realm.Realm
+import io.realm.RealmConfiguration
+import io.realm.kotlin.createObject
+import io.realm.kotlin.where
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.contentscanner.ScanState
+import org.matrix.android.sdk.api.session.contentscanner.ScanStatusInfo
+import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.api.util.toOptional
+import org.matrix.android.sdk.internal.di.ContentScannerDatabase
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.contentscanner.data.ContentScannerStore
+import org.matrix.android.sdk.internal.util.isValidUrl
+import javax.inject.Inject
+
+@SessionScope
+internal class RealmContentScannerStore @Inject constructor(
+        @ContentScannerDatabase
+        private val realmConfiguration: RealmConfiguration
+) : ContentScannerStore {
+
+    private val monarchy = Monarchy.Builder()
+            .setRealmConfiguration(realmConfiguration)
+            .build()
+
+    override fun getScannerUrl(): String? {
+        return monarchy.fetchAllMappedSync(
+                { realm ->
+                    realm.where<ContentScannerInfoEntity>()
+                }, {
+            it.serverUrl
+        }
+        ).firstOrNull()
+    }
+
+    override fun setScannerUrl(url: String?) {
+        monarchy.runTransactionSync { realm ->
+            val info = realm.where<ContentScannerInfoEntity>().findFirst()
+                    ?: realm.createObject()
+            info.serverUrl = url
+        }
+    }
+
+    override fun enableScanner(enabled: Boolean) {
+        monarchy.runTransactionSync { realm ->
+            val info = realm.where<ContentScannerInfoEntity>().findFirst()
+                    ?: realm.createObject()
+            info.enabled = enabled
+        }
+    }
+
+    override fun isScanEnabled(): Boolean {
+        return monarchy.fetchAllMappedSync(
+                { realm ->
+                    realm.where<ContentScannerInfoEntity>()
+                }, {
+            it.enabled.orFalse() && it.serverUrl?.isValidUrl().orFalse()
+        }
+        ).firstOrNull().orFalse()
+    }
+
+    override fun updateStateForContent(mxcUrl: String, state: ScanState, scannerUrl: String?) {
+        monarchy.runTransactionSync {
+            ContentScanResultEntity.getOrCreate(it, mxcUrl, scannerUrl).scanResult = state
+        }
+    }
+
+    override fun updateScanResultForContent(mxcUrl: String, scannerUrl: String?, state: ScanState, humanReadable: String) {
+        monarchy.runTransactionSync {
+            ContentScanResultEntity.getOrCreate(it, mxcUrl, scannerUrl).apply {
+                scanResult = state
+                scanDateTimestamp = System.currentTimeMillis()
+                humanReadableMessage = humanReadable
+            }
+        }
+    }
+
+    override fun isScanResultKnownOrInProgress(mxcUrl: String, scannerUrl: String?): Boolean {
+        var isKnown = false
+        monarchy.runTransactionSync {
+            val info = ContentScanResultEntity.get(it, mxcUrl, scannerUrl)?.scanResult
+            isKnown = when (info) {
+                ScanState.IN_PROGRESS,
+                ScanState.TRUSTED,
+                ScanState.INFECTED -> true
+                else               -> false
+            }
+        }
+        return isKnown
+    }
+
+    override fun getScanResult(mxcUrl: String): ScanStatusInfo? {
+        return monarchy.fetchAllMappedSync({ realm ->
+            realm.where<ContentScanResultEntity>()
+                    .equalTo(ContentScanResultEntityFields.MEDIA_URL, mxcUrl)
+                    .apply {
+                        getScannerUrl()?.let {
+                            equalTo(ContentScanResultEntityFields.SCANNER_URL, it)
+                        }
+                    }
+        }, {
+            it.toModel()
+        })
+                .firstOrNull()
+    }
+
+    override fun getLiveScanResult(mxcUrl: String): LiveData<Optional<ScanStatusInfo>> {
+        val liveData = monarchy.findAllMappedWithChanges(
+                { realm: Realm ->
+                    realm.where<ContentScanResultEntity>()
+                            .equalTo(ContentScanResultEntityFields.MEDIA_URL, mxcUrl)
+                            .equalTo(ContentScanResultEntityFields.SCANNER_URL, getScannerUrl())
+                },
+                { entity ->
+                    entity.toModel()
+                }
+        )
+        return Transformations.map(liveData) {
+            it.firstOrNull().toOptional()
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/DownloadBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/DownloadBody.kt
new file mode 100644
index 0000000000..5bac96a0c0
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/DownloadBody.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
+import org.matrix.android.sdk.internal.di.MoshiProvider
+import org.matrix.android.sdk.internal.util.JsonCanonicalizer
+
+@JsonClass(generateAdapter = true)
+internal data class DownloadBody(
+        @Json(name = "file") val file: EncryptedFileInfo? = null,
+        @Json(name = "encrypted_body") val encryptedBody: EncryptedBody? = null
+)
+
+@JsonClass(generateAdapter = true)
+internal data class EncryptedBody(
+        @Json(name = "ciphertext") val cipherText: String,
+        @Json(name = "mac") val mac: String,
+        @Json(name = "ephemeral") val ephemeral: String
+)
+
+internal fun DownloadBody.toJson(): String = MoshiProvider.providesMoshi().adapter(DownloadBody::class.java).toJson(this)
+
+internal fun DownloadBody.toCanonicalJson() = JsonCanonicalizer.getCanonicalJson(DownloadBody::class.java, this)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt
new file mode 100644
index 0000000000..f783fe0a6c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * {
+ *      "clean": true,
+ *      "info": "File clean at 6/7/2018, 6:02:40 PM"
+ *  }
+ */
+@JsonClass(generateAdapter = true)
+internal data class ScanResponse(
+        @Json(name = "clean") val clean: Boolean,
+        /** Human-readable information about the result. */
+        @Json(name = "info") val info: String?
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ServerPublicKeyResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ServerPublicKeyResponse.kt
new file mode 100644
index 0000000000..2e97a85bca
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ServerPublicKeyResponse.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+internal data class ServerPublicKeyResponse(
+        @Json(name = "public_key")
+        val publicKey: String?
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/DownloadEncryptedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/DownloadEncryptedTask.kt
new file mode 100644
index 0000000000..f92c869cb8
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/DownloadEncryptedTask.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.tasks
+
+import okhttp3.ResponseBody
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerApiProvider
+import org.matrix.android.sdk.internal.session.contentscanner.ScanEncryptorUtils
+import org.matrix.android.sdk.internal.task.Task
+import javax.inject.Inject
+
+internal interface DownloadEncryptedTask : Task<DownloadEncryptedTask.Params, ResponseBody> {
+    data class Params(
+            val publicServerKey: String?,
+            val encryptedInfo: ElementToDecrypt,
+            val mxcUrl: String
+    )
+}
+
+internal class DefaultDownloadEncryptedTask @Inject constructor(
+        private val contentScannerApiProvider: ContentScannerApiProvider
+) : DownloadEncryptedTask {
+
+    override suspend fun execute(params: DownloadEncryptedTask.Params): ResponseBody {
+        val dlBody = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded(
+                params.publicServerKey,
+                params.mxcUrl,
+                params.encryptedInfo
+        )
+
+        val api = contentScannerApiProvider.contentScannerApi ?: throw IllegalArgumentException()
+        return executeRequest(null) {
+            api.downloadEncrypted(dlBody)
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/GetServerPublicKeyTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/GetServerPublicKeyTask.kt
new file mode 100644
index 0000000000..41c2ec9c38
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/GetServerPublicKeyTask.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.tasks
+
+import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerApi
+import org.matrix.android.sdk.internal.session.contentscanner.model.ServerPublicKeyResponse
+import org.matrix.android.sdk.internal.task.Task
+import javax.inject.Inject
+
+internal interface GetServerPublicKeyTask : Task<GetServerPublicKeyTask.Params, String?> {
+    data class Params(
+            val contentScannerApi: ContentScannerApi
+    )
+}
+
+internal class DefaultGetServerPublicKeyTask @Inject constructor() : GetServerPublicKeyTask {
+
+    override suspend fun execute(params: GetServerPublicKeyTask.Params): String? {
+        return executeRequest<ServerPublicKeyResponse>(null) {
+            params.contentScannerApi.getServerPublicKey()
+        }.publicKey
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt
new file mode 100644
index 0000000000..dab9b5538f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanEncryptedTask.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.tasks
+
+import org.matrix.android.sdk.api.failure.toScanFailure
+import org.matrix.android.sdk.api.session.contentscanner.ScanState
+import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
+import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerApiProvider
+import org.matrix.android.sdk.internal.session.contentscanner.ScanEncryptorUtils
+import org.matrix.android.sdk.internal.session.contentscanner.data.ContentScannerStore
+import org.matrix.android.sdk.internal.session.contentscanner.model.ScanResponse
+import org.matrix.android.sdk.internal.task.Task
+import javax.inject.Inject
+
+internal interface ScanEncryptedTask : Task<ScanEncryptedTask.Params, ScanResponse> {
+    data class Params(
+            val mxcUrl: String,
+            val publicServerKey: String?,
+            val encryptedInfo: ElementToDecrypt
+    )
+}
+
+internal class DefaultScanEncryptedTask @Inject constructor(
+        private val contentScannerApiProvider: ContentScannerApiProvider,
+        private val contentScannerStore: ContentScannerStore
+) : ScanEncryptedTask {
+
+    override suspend fun execute(params: ScanEncryptedTask.Params): ScanResponse {
+        val mxcUrl = params.mxcUrl
+        val dlBody = ScanEncryptorUtils.getDownloadBodyAndEncryptIfNeeded(params.publicServerKey, params.mxcUrl, params.encryptedInfo)
+
+        val scannerUrl = contentScannerStore.getScannerUrl()
+        contentScannerStore.updateStateForContent(params.mxcUrl, ScanState.IN_PROGRESS, scannerUrl)
+
+        try {
+            val api = contentScannerApiProvider.contentScannerApi ?: throw IllegalArgumentException()
+            val executeRequest = executeRequest<ScanResponse>(null) {
+                api.scanFile(dlBody)
+            }
+            contentScannerStore.updateScanResultForContent(
+                    mxcUrl,
+                    scannerUrl,
+                    ScanState.TRUSTED.takeIf { executeRequest.clean } ?: ScanState.INFECTED,
+                    executeRequest.info ?: ""
+            )
+            return executeRequest
+        } catch (failure: Throwable) {
+            contentScannerStore.updateStateForContent(params.mxcUrl, ScanState.UNKNOWN, scannerUrl)
+            throw failure.toScanFailure() ?: failure
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanMediaTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanMediaTask.kt
new file mode 100644
index 0000000000..505eb7098c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/tasks/ScanMediaTask.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.contentscanner.tasks
+
+import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl
+import org.matrix.android.sdk.api.MatrixUrls.removeMxcPrefix
+import org.matrix.android.sdk.api.failure.toScanFailure
+import org.matrix.android.sdk.api.session.contentscanner.ScanState
+import org.matrix.android.sdk.internal.network.executeRequest
+import org.matrix.android.sdk.internal.session.contentscanner.ContentScannerApiProvider
+import org.matrix.android.sdk.internal.session.contentscanner.data.ContentScannerStore
+import org.matrix.android.sdk.internal.session.contentscanner.model.ScanResponse
+import org.matrix.android.sdk.internal.task.Task
+import javax.inject.Inject
+
+internal interface ScanMediaTask : Task<ScanMediaTask.Params, ScanResponse> {
+    data class Params(
+            val mxcUrl: String
+    )
+}
+
+internal class DefaultScanMediaTask @Inject constructor(
+        private val contentScannerApiProvider: ContentScannerApiProvider,
+        private val contentScannerStore: ContentScannerStore
+) : ScanMediaTask {
+
+    override suspend fun execute(params: ScanMediaTask.Params): ScanResponse {
+        // "mxc://server.org/QNDpzLopkoQYNikJfoZCQuCXJ"
+        if (!params.mxcUrl.isMxcUrl()) {
+            throw IllegalAccessException("Invalid mxc url")
+        }
+        val scannerUrl = contentScannerStore.getScannerUrl()
+        contentScannerStore.updateStateForContent(params.mxcUrl, ScanState.IN_PROGRESS, scannerUrl)
+
+        var serverAndMediaId = params.mxcUrl.removeMxcPrefix()
+        val fragmentOffset = serverAndMediaId.indexOf("#")
+        if (fragmentOffset >= 0) {
+            serverAndMediaId = serverAndMediaId.substring(0, fragmentOffset)
+        }
+
+        val split = serverAndMediaId.split("/")
+        if (split.size != 2) {
+            throw IllegalAccessException("Invalid mxc url")
+        }
+
+        try {
+            val scanResponse = executeRequest<ScanResponse>(null) {
+                val api = contentScannerApiProvider.contentScannerApi ?: throw IllegalArgumentException()
+                api.scanMedia(split[0], split[1])
+            }
+            contentScannerStore.updateScanResultForContent(
+                    params.mxcUrl,
+                    scannerUrl,
+                    ScanState.TRUSTED.takeIf { scanResponse.clean } ?: ScanState.INFECTED,
+                    scanResponse.info ?: ""
+            )
+            return scanResponse
+        } catch (failure: Throwable) {
+            contentScannerStore.updateStateForContent(params.mxcUrl, ScanState.UNKNOWN, scannerUrl)
+            throw failure.toScanFailure() ?: failure
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroupService.kt
index 8dc5f3931d..9334d09377 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroupService.kt
@@ -30,12 +30,16 @@ import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
 import org.matrix.android.sdk.internal.database.model.GroupSummaryEntityFields
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
+import org.matrix.android.sdk.internal.query.QueryStringValueProcessor
 import org.matrix.android.sdk.internal.query.process
 import org.matrix.android.sdk.internal.util.fetchCopyMap
 import javax.inject.Inject
 
-internal class DefaultGroupService @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                       private val groupFactory: GroupFactory) : GroupService {
+internal class DefaultGroupService @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val groupFactory: GroupFactory,
+        private val queryStringValueProcessor: QueryStringValueProcessor,
+) : GroupService {
 
     override fun getGroup(groupId: String): Group? {
         return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
@@ -67,8 +71,10 @@ internal class DefaultGroupService @Inject constructor(@SessionDatabase private
     }
 
     private fun groupSummariesQuery(realm: Realm, queryParams: GroupSummaryQueryParams): RealmQuery<GroupSummaryEntity> {
-        return GroupSummaryEntity.where(realm)
-                .process(GroupSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
-                .process(GroupSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
+        return with(queryStringValueProcessor) {
+            GroupSummaryEntity.where(realm)
+                    .process(GroupSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
+                    .process(GroupSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
+        }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
index 37d9a4e74f..c8a9c0f09a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
@@ -80,7 +80,7 @@ internal class DefaultIdentityService @Inject constructor(
         private val identityApiProvider: IdentityApiProvider,
         private val accountDataDataSource: UserAccountDataDataSource,
         private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
-        private val sign3pidInvitationTask: DefaultSign3pidInvitationTask,
+        private val sign3pidInvitationTask: Sign3pidInvitationTask,
         private val sessionParams: SessionParams
 ) : IdentityService, SessionLifecycleObserver {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt
index 19e602d7a7..65794e6b14 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt
@@ -21,6 +21,7 @@ import dagger.Module
 import dagger.Provides
 import io.realm.RealmConfiguration
 import okhttp3.OkHttpClient
+import org.matrix.android.sdk.api.session.identity.IdentityService
 import org.matrix.android.sdk.internal.database.RealmKeysUtils
 import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
 import org.matrix.android.sdk.internal.di.IdentityDatabase
@@ -75,6 +76,9 @@ internal abstract class IdentityModule {
         }
     }
 
+    @Binds
+    abstract fun bindIdentityService(service: DefaultIdentityService): IdentityService
+
     @Binds
     @AuthenticatedIdentity
     abstract fun bindAccessTokenProvider(provider: IdentityAccessTokenProvider): AccessTokenProvider
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt
index 65974151c8..3e821b8956 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt
@@ -19,6 +19,7 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.Transformations
 import com.zhuinden.monarchy.Monarchy
 import org.matrix.android.sdk.api.pushrules.Action
+import org.matrix.android.sdk.api.pushrules.PushEvents
 import org.matrix.android.sdk.api.pushrules.PushRuleService
 import org.matrix.android.sdk.api.pushrules.RuleKind
 import org.matrix.android.sdk.api.pushrules.RuleScope
@@ -142,79 +143,6 @@ internal class DefaultPushRuleService @Inject constructor(
         return pushRuleFinder.fulfilledBingRule(event, rules)?.getActions().orEmpty()
     }
 
-//    fun processEvents(events: List<Event>) {
-//        var hasDoneSomething = false
-//        events.forEach { event ->
-//            fulfilledBingRule(event)?.let {
-//                hasDoneSomething = true
-//                dispatchBing(event, it)
-//            }
-//        }
-//        if (hasDoneSomething)
-//            dispatchFinish()
-//    }
-
-    fun dispatchBing(event: Event, rule: PushRule) {
-        synchronized(listeners) {
-            val actionsList = rule.getActions()
-            listeners.forEach {
-                try {
-                    it.onMatchRule(event, actionsList)
-                } catch (e: Throwable) {
-                    Timber.e(e, "Error while dispatching bing")
-                }
-            }
-        }
-    }
-
-    fun dispatchRoomJoined(roomId: String) {
-        synchronized(listeners) {
-            listeners.forEach {
-                try {
-                    it.onRoomJoined(roomId)
-                } catch (e: Throwable) {
-                    Timber.e(e, "Error while dispatching room joined")
-                }
-            }
-        }
-    }
-
-    fun dispatchRoomLeft(roomId: String) {
-        synchronized(listeners) {
-            listeners.forEach {
-                try {
-                    it.onRoomLeft(roomId)
-                } catch (e: Throwable) {
-                    Timber.e(e, "Error while dispatching room left")
-                }
-            }
-        }
-    }
-
-    fun dispatchRedactedEventId(redactedEventId: String) {
-        synchronized(listeners) {
-            listeners.forEach {
-                try {
-                    it.onEventRedacted(redactedEventId)
-                } catch (e: Throwable) {
-                    Timber.e(e, "Error while dispatching redacted event")
-                }
-            }
-        }
-    }
-
-    fun dispatchFinish() {
-        synchronized(listeners) {
-            listeners.forEach {
-                try {
-                    it.batchFinish()
-                } catch (e: Throwable) {
-                    Timber.e(e, "Error while dispatching finish")
-                }
-            }
-        }
-    }
-
     override fun getKeywords(): LiveData<Set<String>> {
         // Keywords are all content rules that don't start with '.'
         val liveData = monarchy.findAllMappedWithChanges(
@@ -229,4 +157,16 @@ internal class DefaultPushRuleService @Inject constructor(
             results.firstOrNull().orEmpty().toSet()
         }
     }
+
+    fun dispatchEvents(pushEvents: PushEvents) {
+        synchronized(listeners) {
+            listeners.forEach {
+                try {
+                    it.onEvents(pushEvents)
+                } catch (e: Throwable) {
+                    Timber.e(e, "Error while dispatching push events")
+                }
+            }
+        }
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt
index 1321f8dd62..0ac21b555e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt
@@ -16,8 +16,10 @@
 
 package org.matrix.android.sdk.internal.session.notification
 
+import org.matrix.android.sdk.api.pushrules.PushEvents
 import org.matrix.android.sdk.api.pushrules.rest.PushRule
 import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.isInvitation
 import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
 import org.matrix.android.sdk.internal.di.UserId
 import org.matrix.android.sdk.internal.task.Task
@@ -38,24 +40,20 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
 ) : ProcessEventForPushTask {
 
     override suspend fun execute(params: ProcessEventForPushTask.Params) {
-        // Handle left rooms
-        params.syncResponse.leave.keys.forEach {
-            defaultPushRuleService.dispatchRoomLeft(it)
-        }
-        // Handle joined rooms
-        params.syncResponse.join.keys.forEach {
-            defaultPushRuleService.dispatchRoomJoined(it)
-        }
         val newJoinEvents = params.syncResponse.join
                 .mapNotNull { (key, value) ->
-                    value.timeline?.events?.map { it.copy(roomId = key) }
+                    value.timeline?.events?.mapNotNull {
+                        it.takeIf { !it.isInvitation() }?.copy(roomId = key)
+                    }
                 }
                 .flatten()
+
         val inviteEvents = params.syncResponse.invite
                 .mapNotNull { (key, value) ->
                     value.inviteState?.events?.map { it.copy(roomId = key) }
                 }
                 .flatten()
+
         val allEvents = (newJoinEvents + inviteEvents).filter { event ->
             when (event.type) {
                 EventType.MESSAGE,
@@ -69,10 +67,10 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
         }
         Timber.v("[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" +
                 " to check for push rules with ${params.rules.size} rules")
-        allEvents.forEach { event ->
+        val matchedEvents = allEvents.mapNotNull { event ->
             pushRuleFinder.fulfilledBingRule(event, params.rules)?.let {
                 Timber.v("[PushRules] Rule $it match for event ${event.eventId}")
-                defaultPushRuleService.dispatchBing(event, it)
+                event to it
             }
         }
 
@@ -86,10 +84,13 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
 
         Timber.v("[PushRules] Found ${allRedactedEvents.size} redacted events")
 
-        allRedactedEvents.forEach { redactedEventId ->
-            defaultPushRuleService.dispatchRedactedEventId(redactedEventId)
-        }
-
-        defaultPushRuleService.dispatchFinish()
+        defaultPushRuleService.dispatchEvents(
+                PushEvents(
+                        matchedEvents = matchedEvents,
+                        roomsJoined = params.syncResponse.join.keys,
+                        roomsLeft = params.syncResponse.leave.keys,
+                        redactedEventIds = allRedactedEvents
+                )
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
index 5b2499c130..7ca64aa66a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
@@ -85,12 +85,14 @@ internal class DefaultRoomService @Inject constructor(
         return roomSummaryDataSource.getRoomSummary(roomIdOrAlias)
     }
 
-    override fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List<RoomSummary> {
-        return roomSummaryDataSource.getRoomSummaries(queryParams)
+    override fun getRoomSummaries(queryParams: RoomSummaryQueryParams,
+                                  sortOrder: RoomSortOrder): List<RoomSummary> {
+        return roomSummaryDataSource.getRoomSummaries(queryParams, sortOrder)
     }
 
-    override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>> {
-        return roomSummaryDataSource.getRoomSummariesLive(queryParams)
+    override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams,
+                                      sortOrder: RoomSortOrder): LiveData<List<RoomSummary>> {
+        return roomSummaryDataSource.getRoomSummariesLive(queryParams, sortOrder)
     }
 
     override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
index 0e4493846c..d96beed3f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
@@ -43,7 +43,7 @@ internal class RoomAccountDataDataSource @Inject constructor(@SessionDatabase pr
 
     fun getLiveAccountDataEvent(roomId: String, type: String): LiveData<Optional<RoomAccountDataEvent>> {
         return Transformations.map(getLiveAccountDataEvents(roomId, setOf(type))) {
-            it.firstOrNull()?.toOptional()
+            it.firstOrNull().toOptional()
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt
index 204deb72b4..6cf82dde44 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/DefaultMembershipService.kt
@@ -33,6 +33,7 @@ import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
 import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.query.QueryStringValueProcessor
 import org.matrix.android.sdk.internal.query.process
 import org.matrix.android.sdk.internal.session.room.membership.admin.MembershipAdminTask
 import org.matrix.android.sdk.internal.session.room.membership.joining.InviteTask
@@ -51,7 +52,8 @@ internal class DefaultMembershipService @AssistedInject constructor(
         private val leaveRoomTask: LeaveRoomTask,
         private val membershipAdminTask: MembershipAdminTask,
         @UserId
-        private val userId: String
+        private val userId: String,
+        private val queryStringValueProcessor: QueryStringValueProcessor
 ) : MembershipService {
 
     @AssistedFactory
@@ -94,15 +96,17 @@ internal class DefaultMembershipService @AssistedInject constructor(
     }
 
     private fun roomMembersQuery(realm: Realm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> {
-        return RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
-                .process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId)
-                .process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
-                .process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
-                .apply {
-                    if (queryParams.excludeSelf) {
-                        notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
+        return with(queryStringValueProcessor) {
+            RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
+                    .process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId)
+                    .process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
+                    .process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
+                    .apply {
+                        if (queryParams.excludeSelf) {
+                            notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
+                        }
                     }
-                }
+        }
     }
 
     override fun getNumberOfJoinedMembers(): Int {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
index 5e77dd157a..bd9f2ecc36 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
@@ -34,6 +34,7 @@ import org.matrix.android.sdk.internal.database.query.getOrNull
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.UserId
 import org.matrix.android.sdk.internal.session.displayname.DisplayNameResolver
+import org.matrix.android.sdk.internal.util.Normalizer
 import javax.inject.Inject
 
 /**
@@ -42,6 +43,7 @@ import javax.inject.Inject
 internal class RoomDisplayNameResolver @Inject constructor(
         matrixConfiguration: MatrixConfiguration,
         private val displayNameResolver: DisplayNameResolver,
+        private val normalizer: Normalizer,
         @UserId private val userId: String
 ) {
 
@@ -54,7 +56,7 @@ internal class RoomDisplayNameResolver @Inject constructor(
      * @param roomId: the roomId to resolve the name of.
      * @return the room display name
      */
-    fun resolve(realm: Realm, roomId: String): String {
+    fun resolve(realm: Realm, roomId: String): RoomName {
         // this algorithm is the one defined in
         // https://github.com/matrix-org/matrix-js-sdk/blob/develop/lib/models/room.js#L617
         // calculateRoomName(room, userId)
@@ -66,12 +68,12 @@ internal class RoomDisplayNameResolver @Inject constructor(
         val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root
         name = ContentMapper.map(roomName?.content).toModel<RoomNameContent>()?.name
         if (!name.isNullOrEmpty()) {
-            return name
+            return name.toRoomName()
         }
         val canonicalAlias = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root
         name = ContentMapper.map(canonicalAlias?.content).toModel<RoomCanonicalAliasContent>()?.canonicalAlias
         if (!name.isNullOrEmpty()) {
-            return name
+            return name.toRoomName()
         }
 
         val roomMembers = RoomMemberHelper(realm, roomId)
@@ -152,7 +154,7 @@ internal class RoomDisplayNameResolver @Inject constructor(
                 }
             }
         }
-        return name ?: roomId
+        return (name ?: roomId).toRoomName()
     }
 
     /** See [org.matrix.android.sdk.api.session.room.sender.SenderInfo.disambiguatedDisplayName] */
@@ -165,4 +167,8 @@ internal class RoomDisplayNameResolver @Inject constructor(
             "${roomMemberSummary.displayName} (${roomMemberSummary.userId})"
         }
     }
+
+    private fun String.toRoomName() = RoomName(this, normalizedName = normalizer.normalize(this))
 }
+
+internal data class RoomName(val name: String, val normalizedName: String)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
index 177c98541c..77aadef6bd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
@@ -37,7 +37,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
-import org.matrix.android.sdk.api.session.room.model.message.OptionItem
 import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
 import org.matrix.android.sdk.api.session.room.send.SendService
 import org.matrix.android.sdk.api.session.room.send.SendState
@@ -98,7 +97,7 @@ internal class DefaultSendService @AssistedInject constructor(
                 .let { sendEvent(it) }
     }
 
-    override fun sendPoll(question: String, options: List<OptionItem>): Cancelable {
+    override fun sendPoll(question: String, options: List<String>): Cancelable {
         return localEchoEventFactory.createPollEvent(roomId, question, options)
                 .also { createLocalEcho(it) }
                 .let { sendEvent(it) }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
index e49c83e53b..69f2542d12 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
@@ -38,13 +38,14 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithF
 import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
 import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
-import org.matrix.android.sdk.api.session.room.model.message.MessageOptionsContent
+import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
 import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageType
 import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
-import org.matrix.android.sdk.api.session.room.model.message.OPTION_TYPE_POLL
-import org.matrix.android.sdk.api.session.room.model.message.OptionItem
+import org.matrix.android.sdk.api.session.room.model.message.PollAnswer
+import org.matrix.android.sdk.api.session.room.model.message.PollCreationInfo
+import org.matrix.android.sdk.api.session.room.model.message.PollQuestion
 import org.matrix.android.sdk.api.session.room.model.message.ThumbnailInfo
 import org.matrix.android.sdk.api.session.room.model.message.VideoInfo
 import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
@@ -139,24 +140,29 @@ internal class LocalEchoEventFactory @Inject constructor(
 
     fun createPollEvent(roomId: String,
                         question: String,
-                        options: List<OptionItem>): Event {
-        val compatLabel = buildString {
-            append("[Poll] ")
-            append(question)
-            options.forEach {
-                append("\n")
-                append(it.value)
-            }
-        }
-        return createMessageEvent(
-                roomId,
-                MessageOptionsContent(
-                        body = compatLabel,
-                        label = question,
-                        optionType = OPTION_TYPE_POLL,
-                        options = options.toList()
+                        options: List<String>): Event {
+        val content = MessagePollContent(
+                pollCreationInfo = PollCreationInfo(
+                        question = PollQuestion(
+                                question = question
+                        ),
+                        answers = options.mapIndexed { index, option ->
+                            PollAnswer(
+                                    id = index.toString(),
+                                    answer = option
+                            )
+                        }
                 )
         )
+        val localId = LocalEcho.createLocalEchoId()
+        return Event(
+                roomId = roomId,
+                originServerTs = dummyOriginServerTs(),
+                senderId = userId,
+                eventId = localId,
+                type = EventType.POLL_START,
+                content = content.toContent(),
+                unsignedData = UnsignedData(age = null, transactionId = localId))
     }
 
     fun createReplaceTextOfReply(roomId: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt
index a25a362bfa..2114b9c590 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt
@@ -31,11 +31,15 @@ import org.matrix.android.sdk.internal.database.mapper.asDomain
 import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
 import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
 import org.matrix.android.sdk.internal.di.SessionDatabase
+import org.matrix.android.sdk.internal.query.QueryStringValueProcessor
 import org.matrix.android.sdk.internal.query.process
 import javax.inject.Inject
 
-internal class StateEventDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                        private val realmSessionProvider: RealmSessionProvider) {
+internal class StateEventDataSource @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val realmSessionProvider: RealmSessionProvider,
+        private val queryStringValueProcessor: QueryStringValueProcessor
+) {
 
     fun getStateEvent(roomId: String, eventType: String, stateKey: QueryStringValue): Event? {
         return realmSessionProvider.withRealm { realm ->
@@ -78,13 +82,15 @@ internal class StateEventDataSource @Inject constructor(@SessionDatabase private
                                      eventTypes: Set<String>,
                                      stateKey: QueryStringValue
     ): RealmQuery<CurrentStateEventEntity> {
-        return realm.where<CurrentStateEventEntity>()
-                .equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
-                .apply {
-                    if (eventTypes.isNotEmpty()) {
-                        `in`(CurrentStateEventEntityFields.TYPE, eventTypes.toTypedArray())
+        return with(queryStringValueProcessor) {
+            realm.where<CurrentStateEventEntity>()
+                    .equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
+                    .apply {
+                        if (eventTypes.isNotEmpty()) {
+                            `in`(CurrentStateEventEntityFields.TYPE, eventTypes.toTypedArray())
+                        }
                     }
-                }
-                .process(CurrentStateEventEntityFields.STATE_KEY, stateKey)
+                    .process(CurrentStateEventEntityFields.STATE_KEY, stateKey)
+        }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
index 7b2dd932b2..7cf5265826 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
@@ -26,10 +26,10 @@ import com.zhuinden.monarchy.Monarchy
 import de.spiritcroc.matrixsdk.StaticScSdkHelper
 import io.realm.Realm
 import io.realm.RealmQuery
-import io.realm.Sort
 import io.realm.kotlin.where
 import org.matrix.android.sdk.api.query.ActiveSpaceFilter
 import org.matrix.android.sdk.api.query.RoomCategoryFilter
+import org.matrix.android.sdk.api.query.isNormalized
 import org.matrix.android.sdk.api.session.room.ResultBoundaries
 import org.matrix.android.sdk.api.session.room.RoomSortOrder
 import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
@@ -49,13 +49,17 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
 import org.matrix.android.sdk.internal.database.query.findByAlias
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
+import org.matrix.android.sdk.internal.query.QueryStringValueProcessor
 import org.matrix.android.sdk.internal.query.process
 import org.matrix.android.sdk.internal.util.fetchCopyMap
 import javax.inject.Inject
 import kotlin.math.max
 
-internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                         private val roomSummaryMapper: RoomSummaryMapper) {
+internal class RoomSummaryDataSource @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val roomSummaryMapper: RoomSummaryMapper,
+        private val queryStringValueProcessor: QueryStringValueProcessor
+) {
 
     fun getRoomSummary(roomIdOrAlias: String): RoomSummary? {
         return monarchy
@@ -82,25 +86,27 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
         }
     }
 
-    fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List<RoomSummary> {
+    fun getRoomSummaries(queryParams: RoomSummaryQueryParams,
+                         sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> {
         return monarchy.fetchAllMappedSync(
-                { roomSummariesQuery(it, queryParams) },
+                { roomSummariesQuery(it, queryParams).process(sortOrder) },
                 { roomSummaryMapper.map(it) }
         )
     }
 
-    fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>> {
+    fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams,
+                             sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> {
         return monarchy.findAllMappedWithChanges(
                 {
-                    roomSummariesQuery(it, queryParams)
-                            .sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
+                    roomSummariesQuery(it, queryParams).process(sortOrder)
                 },
                 { roomSummaryMapper.map(it) }
         )
     }
 
-    fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData<List<RoomSummary>> {
-        return getRoomSummariesLive(queryParams)
+    fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams,
+                              sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> {
+        return getRoomSummariesLive(queryParams, sortOrder)
     }
 
     fun getSpaceSummary(roomIdOrAlias: String): RoomSummary? {
@@ -124,8 +130,9 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
         }
     }
 
-    fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams): List<RoomSummary> {
-        return getRoomSummaries(spaceSummaryQueryParams)
+    fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams,
+                          sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> {
+        return getRoomSummaries(spaceSummaryQueryParams, sortOrder)
     }
 
     fun getRootSpaceSummaries(): List<RoomSummary> {
@@ -266,12 +273,20 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat
     }
 
     private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
-        val query = RoomSummaryEntity.where(realm)
-        query.process(RoomSummaryEntityFields.ROOM_ID, queryParams.roomId)
-        query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
-        query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
-        query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
-        query.equalTo(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, false)
+        val query = with(queryStringValueProcessor) {
+            RoomSummaryEntity.where(realm)
+                    .process(RoomSummaryEntityFields.ROOM_ID, queryParams.roomId)
+                    .let {
+                        if (queryParams.displayName.isNormalized()) {
+                            it.process(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, queryParams.displayName)
+                        } else {
+                            it.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
+                        }
+                    }
+                    .process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
+                    .process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
+                    .equalTo(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, false)
+        }
 
         queryParams.roomCategoryFilter?.let {
             when (it) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
index 30a6d640a7..068fcdd33c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
@@ -66,6 +66,7 @@ import org.matrix.android.sdk.internal.session.room.accountdata.RoomAccountDataD
 import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
 import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
 import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo
+import org.matrix.android.sdk.internal.util.Normalizer
 import timber.log.Timber
 import javax.inject.Inject
 import kotlin.math.min
@@ -77,7 +78,8 @@ internal class RoomSummaryUpdater @Inject constructor(
         private val roomAvatarResolver: RoomAvatarResolver,
         private val eventDecryptor: EventDecryptor,
         private val crossSigningService: DefaultCrossSigningService,
-        private val roomAccountDataDataSource: RoomAccountDataDataSource) {
+        private val roomAccountDataDataSource: RoomAccountDataDataSource,
+        private val normalizer: Normalizer) {
 
     fun update(realm: Realm,
                roomId: String,
@@ -160,7 +162,7 @@ internal class RoomSummaryUpdater @Inject constructor(
                 (latestPreviewableOriginalContentEvent != null &&
                         !isEventRead(realm.configuration, userId, roomId, latestPreviewableOriginalContentEvent.eventId))
 
-        roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(realm, roomId)
+        roomSummaryEntity.setDisplayName(roomDisplayNameResolver.resolve(realm, roomId))
         roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId)
         roomSummaryEntity.name = ContentMapper.map(lastNameEvent?.content).toModel<RoomNameContent>()?.name
         roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel<RoomTopicContent>()?.topic
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt
index 563e85aefc..42fdf30501 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignInAgainTask.kt
@@ -42,11 +42,12 @@ internal class DefaultSignInAgainTask @Inject constructor(
             signOutAPI.loginAgain(
                     PasswordLoginParams.userIdentifier(
                             // Reuse the same userId
-                            sessionParams.userId,
-                            params.password,
+                            user = sessionParams.userId,
+                            password = params.password,
                             // The spec says the initial device name will be ignored
                             // https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-login
                             // but https://github.com/matrix-org/synapse/issues/6525
+                            deviceDisplayName = null,
                             // Reuse the same deviceId
                             deviceId = sessionParams.deviceId
                     )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt
index 19f34746ab..7ac34e80e9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt
@@ -43,6 +43,7 @@ internal class DefaultSignOutTask @Inject constructor(
     override suspend fun execute(params: SignOutTask.Params) {
         // It should be done even after a soft logout, to be sure the deviceId is deleted on the
         if (params.signOutFromHomeserver) {
+            cleanupSession.stopActiveTasks()
             Timber.d("SignOut: send request...")
             try {
                 executeRequest(globalErrorReceiver) {
@@ -67,6 +68,6 @@ internal class DefaultSignOutTask @Inject constructor(
                 .onFailure { Timber.w(it, "Unable to disconnect identity server") }
 
         Timber.d("SignOut: cleanup session...")
-        cleanupSession.handle()
+        cleanupSession.cleanup()
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
index ac20c79058..ebd5f2578e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
@@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toContent
 import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.session.room.RoomSortOrder
 import org.matrix.android.sdk.api.session.room.model.GuestAccess
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
@@ -94,12 +95,14 @@ internal class DefaultSpaceService @Inject constructor(
         return spaceGetter.get(spaceId)
     }
 
-    override fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData<List<RoomSummary>> {
-        return roomSummaryDataSource.getSpaceSummariesLive(queryParams)
+    override fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams,
+                                       sortOrder: RoomSortOrder): LiveData<List<RoomSummary>> {
+        return roomSummaryDataSource.getSpaceSummariesLive(queryParams, sortOrder)
     }
 
-    override fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams): List<RoomSummary> {
-        return roomSummaryDataSource.getSpaceSummaries(spaceSummaryQueryParams)
+    override fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams,
+                                   sortOrder: RoomSortOrder): List<RoomSummary> {
+        return roomSummaryDataSource.getSpaceSummaries(spaceSummaryQueryParams, sortOrder)
     }
 
     override fun getRootSpaceSummaries(): List<RoomSummary> {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt
index e8f74bbd48..8c68e224dc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt
@@ -39,8 +39,11 @@ internal class RoomSyncEphemeralTemporaryStoreFile @Inject constructor(
         moshi: Moshi
 ) : RoomSyncEphemeralTemporaryStore {
 
-    private val workingDir = File(fileDirectory, "rr")
-            .also { it.mkdirs() }
+    private val workingDir: File by lazy {
+        File(fileDirectory, "rr").also {
+            it.mkdirs()
+        }
+    }
 
     private val roomSyncEphemeralAdapter = moshi.adapter(RoomSyncEphemeral::class.java)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
index 335f619623..8fd969e373 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
@@ -24,11 +24,13 @@ import org.matrix.android.sdk.api.session.initsync.InitSyncStep
 import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
 import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
 import org.matrix.android.sdk.api.session.sync.model.SyncResponse
+import org.matrix.android.sdk.internal.SessionManager
 import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.di.SessionId
 import org.matrix.android.sdk.internal.di.WorkManagerProvider
 import org.matrix.android.sdk.internal.session.SessionListeners
+import org.matrix.android.sdk.internal.session.dispatchTo
 import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
 import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
 import org.matrix.android.sdk.internal.session.initsync.reportSubtask
@@ -51,6 +53,7 @@ private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
 internal class SyncResponseHandler @Inject constructor(
         @SessionDatabase private val monarchy: Monarchy,
         @SessionId private val sessionId: String,
+        private val sessionManager: SessionManager,
         private val sessionListeners: SessionListeners,
         private val workManagerProvider: WorkManagerProvider,
         private val roomSyncHandler: RoomSyncHandler,
@@ -158,8 +161,9 @@ internal class SyncResponseHandler @Inject constructor(
     }
 
     private fun dispatchInvitedRoom(roomsSyncResponse: RoomsSyncResponse) {
+        val session = sessionManager.getSessionComponent(sessionId)?.session()
         roomsSyncResponse.invite.keys.forEach { roomId ->
-            sessionListeners.dispatch { session, listener ->
+            session.dispatchTo(sessionListeners) { session, listener ->
                 listener.onNewInvitedRoom(session, roomId)
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt
index 3e38cd7839..7f80486c70 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt
@@ -166,7 +166,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
                     roomSummaryEntity.directUserId = userId
                     // Also update the avatar and displayname, there is a specific treatment for DMs
                     roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId)
-                    roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(realm, roomId)
+                    roomSummaryEntity.setDisplayName(roomDisplayNameResolver.resolve(realm, roomId))
                 }
             }
         }
@@ -178,7 +178,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
                     it.directUserId = null
                     // Also update the avatar and displayname, there was a specific treatment for DMs
                     it.avatarUrl = roomAvatarResolver.resolve(realm, it.roomId)
-                    it.displayName = roomDisplayNameResolver.resolve(realm, it.roomId)
+                    it.setDisplayName(roomDisplayNameResolver.resolve(realm, it.roomId))
                 }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt
index 9480cc73f1..c17b31b910 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt
@@ -105,9 +105,8 @@ abstract class SyncService : Service() {
                 }
             }
         }
-
-        // It's ok to be not sticky because we will explicitly start it again on the next alarm?
-        return START_NOT_STICKY
+        // Attempt to continue scheduling syncs after killed service is restarted
+        return START_REDELIVER_INTENT
     }
 
     override fun onDestroy() {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
index e1150f2c47..3faa0c9488 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
@@ -160,6 +160,9 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
                 synchronized(lock) { lock.wait() }
                 Timber.tag(loggerTag.value).d("...retry")
             } else if (!isTokenValid) {
+                if (state == SyncState.Killing) {
+                    continue
+                }
                 Timber.tag(loggerTag.value).d("Token is invalid. Waiting...")
                 updateStateTo(SyncState.InvalidToken)
                 synchronized(lock) { lock.wait() }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
index b81804feb5..41bb1a44a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
@@ -121,9 +121,9 @@ internal class SyncWorker(context: Context,
                     .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
                     .setInitialDelay(delayInSeconds, TimeUnit.SECONDS)
                     .build()
-
+            // Avoid risking multiple chains of syncs by replacing the existing chain
             workManagerProvider.workManager
-                    .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
+                    .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
         }
 
         fun stopAnyBackgroundSync(workManagerProvider: WorkManagerProvider) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt
index b36bdc80f8..2c3d660333 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt
@@ -41,7 +41,7 @@ internal class UserAccountDataDataSource @Inject constructor(@SessionDatabase pr
 
     fun getLiveAccountDataEvent(type: String): LiveData<Optional<UserAccountDataEvent>> {
         return Transformations.map(getLiveAccountDataEvents(setOf(type))) {
-            it.firstOrNull()?.toOptional()
+            it.firstOrNull().toOptional()
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt
index 7cc00d023f..3e977b31fb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BackgroundDetectionObserver.kt
@@ -16,9 +16,8 @@
 
 package org.matrix.android.sdk.internal.util
 
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import org.matrix.android.sdk.internal.di.MatrixScope
 import timber.log.Timber
 import javax.inject.Inject
@@ -27,13 +26,12 @@ import javax.inject.Inject
  * To be attached to ProcessLifecycleOwner lifecycle
  */
 @MatrixScope
-internal class BackgroundDetectionObserver @Inject constructor() : LifecycleObserver {
+internal class BackgroundDetectionObserver @Inject constructor() : DefaultLifecycleObserver {
 
-    var isInBackground: Boolean = false
+    var isInBackground: Boolean = true
         private set
 
-    private
-    val listeners = LinkedHashSet<Listener>()
+    private val listeners = LinkedHashSet<Listener>()
 
     fun register(listener: Listener) {
         listeners.add(listener)
@@ -43,15 +41,13 @@ internal class BackgroundDetectionObserver @Inject constructor() : LifecycleObse
         listeners.remove(listener)
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_START)
-    fun onMoveToForeground() {
+    override fun onStart(owner: LifecycleOwner) {
         Timber.v("App returning to foreground…")
         isInBackground = false
         listeners.forEach { it.onMoveToForeground() }
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
-    fun onMoveToBackground() {
+    override fun onStop(owner: LifecycleOwner) {
         Timber.v("App going to background…")
         isInBackground = true
         listeners.forEach { it.onMoveToBackground() }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Normalizer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Normalizer.kt
new file mode 100644
index 0000000000..0e9c885394
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Normalizer.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.util
+
+import java.text.Normalizer
+import javax.inject.Inject
+
+class Normalizer @Inject constructor() {
+
+    fun normalize(input: String): String {
+        return Normalizer.normalize(input.lowercase(), Normalizer.Form.NFD)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/call/telecom/TelecomUtils.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigrationTest.kt
similarity index 55%
rename from vector/src/main/java/im/vector/app/features/call/telecom/TelecomUtils.kt
rename to matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigrationTest.kt
index 819a1f6c0a..3a0574e95a 100644
--- a/vector/src/main/java/im/vector/app/features/call/telecom/TelecomUtils.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigrationTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 New Vector Ltd
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,17 +14,16 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.call.telecom
+package org.matrix.android.sdk.internal.database
 
-import android.content.Context
-import android.telephony.TelephonyManager
-import androidx.core.content.getSystemService
+import io.mockk.mockk
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
 
-object TelecomUtils {
+class RealmSessionStoreMigrationTest {
 
-    fun isLineBusy(context: Context): Boolean {
-        val telephonyManager = context.getSystemService<TelephonyManager>()
-                ?: return false
-        return telephonyManager.callState != TelephonyManager.CALL_STATE_IDLE
+    @Test
+    fun `when creating multiple migration instances then they are equal`() {
+        RealmSessionStoreMigration(normalizer = mockk()) shouldBeEqualTo RealmSessionStoreMigration(normalizer = mockk())
     }
 }
diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt
index 315fe6cbf2..2b8c1d11e6 100644
--- a/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt
+++ b/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt
@@ -21,6 +21,7 @@ import android.content.Context
 import android.content.Intent
 import android.provider.ContactsContract
 import im.vector.lib.multipicker.entity.MultiPickerContactType
+import im.vector.lib.multipicker.utils.getColumnIndexOrNull
 
 /**
  * Contact Picker implementation
@@ -49,9 +50,9 @@ class ContactPicker : Picker<MultiPickerContactType>() {
                     null
             )?.use { cursor ->
                 if (cursor.moveToFirst()) {
-                    val idColumn = cursor.getColumnIndex(ContactsContract.Contacts._ID)
-                    val nameColumn = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
-                    val photoUriColumn = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI)
+                    val idColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts._ID) ?: return@use
+                    val nameColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use
+                    val photoUriColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.PHOTO_URI) ?: return@use
 
                     val contactId = cursor.getInt(idColumn)
                     var name = cursor.getString(nameColumn)
@@ -72,10 +73,13 @@ class ContactPicker : Picker<MultiPickerContactType>() {
                                 selection,
                                 selectionArgs,
                                 null
-                        )?.use { cursor ->
-                            while (cursor.moveToNext()) {
-                                val mimeType = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.MIMETYPE))
-                                val contactData = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DATA1))
+                        )?.use inner@{ innerCursor ->
+                            val mimeTypeColumnIndex = innerCursor.getColumnIndexOrNull(ContactsContract.Data.MIMETYPE) ?: return@inner
+                            val data1ColumnIndex = innerCursor.getColumnIndexOrNull(ContactsContract.Data.DATA1) ?: return@inner
+
+                            while (innerCursor.moveToNext()) {
+                                val mimeType = innerCursor.getString(mimeTypeColumnIndex)
+                                val contactData = innerCursor.getString(data1ColumnIndex)
 
                                 if (mimeType == ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) {
                                     name = contactData
@@ -115,7 +119,10 @@ class ContactPicker : Picker<MultiPickerContactType>() {
                 selectionArgs,
                 null
         )?.use { cursor ->
-            return if (cursor.moveToFirst()) cursor.getInt(cursor.getColumnIndex(ContactsContract.RawContacts._ID)) else null
+            return if (cursor.moveToFirst()) {
+                cursor.getColumnIndexOrNull(ContactsContract.RawContacts._ID)
+                        ?.let { cursor.getInt(it) }
+            } else null
         }
     }
 
diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt
index ec98152aa7..8e6c97f2f8 100644
--- a/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt
+++ b/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt
@@ -21,6 +21,7 @@ import android.content.Intent
 import android.provider.OpenableColumns
 import im.vector.lib.multipicker.entity.MultiPickerBaseType
 import im.vector.lib.multipicker.entity.MultiPickerFileType
+import im.vector.lib.multipicker.utils.getColumnIndexOrNull
 import im.vector.lib.multipicker.utils.isMimeTypeAudio
 import im.vector.lib.multipicker.utils.isMimeTypeImage
 import im.vector.lib.multipicker.utils.isMimeTypeVideo
@@ -49,8 +50,8 @@ class FilePicker : Picker<MultiPickerBaseType>() {
                     // Other files
                     context.contentResolver.query(selectedUri, null, null, null, null)
                             ?.use { cursor ->
-                                val nameColumn = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
-                                val sizeColumn = cursor.getColumnIndex(OpenableColumns.SIZE)
+                                val nameColumn = cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME) ?: return@use null
+                                val sizeColumn = cursor.getColumnIndexOrNull(OpenableColumns.SIZE) ?: return@use null
                                 if (cursor.moveToFirst()) {
                                     val name = cursor.getString(nameColumn)
                                     val size = cursor.getLong(sizeColumn)
diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt b/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt
index 67b1ded065..ead6b138be 100644
--- a/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt
+++ b/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt
@@ -38,8 +38,8 @@ internal fun Uri.toMultiPickerImageType(context: Context): MultiPickerImageType?
             null,
             null
     )?.use { cursor ->
-        val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
-        val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
+        val nameColumn = cursor.getColumnIndexOrNull(MediaStore.Images.Media.DISPLAY_NAME) ?: return@use null
+        val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Images.Media.SIZE) ?: return@use null
 
         if (cursor.moveToNext()) {
             val name = cursor.getString(nameColumn)
@@ -76,8 +76,8 @@ internal fun Uri.toMultiPickerVideoType(context: Context): MultiPickerVideoType?
             null,
             null
     )?.use { cursor ->
-        val nameColumn = cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME)
-        val sizeColumn = cursor.getColumnIndex(MediaStore.Video.Media.SIZE)
+        val nameColumn = cursor.getColumnIndexOrNull(MediaStore.Video.Media.DISPLAY_NAME) ?: return@use null
+        val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Video.Media.SIZE) ?: return@use null
 
         if (cursor.moveToNext()) {
             val name = cursor.getString(nameColumn)
@@ -129,8 +129,8 @@ fun Uri.toMultiPickerAudioType(context: Context): MultiPickerAudioType? {
             null,
             null
     )?.use { cursor ->
-        val nameColumn = cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)
-        val sizeColumn = cursor.getColumnIndex(MediaStore.Audio.Media.SIZE)
+        val nameColumn = cursor.getColumnIndexOrNull(MediaStore.Audio.Media.DISPLAY_NAME) ?: return@use null
+        val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Audio.Media.SIZE) ?: return@use null
 
         if (cursor.moveToNext()) {
             val name = cursor.getString(nameColumn)
diff --git a/vector/src/main/java/im/vector/app/core/di/HasScreenInjector.kt b/multipicker/src/main/java/im/vector/lib/multipicker/utils/CursorExtensions.kt
similarity index 65%
rename from vector/src/main/java/im/vector/app/core/di/HasScreenInjector.kt
rename to multipicker/src/main/java/im/vector/lib/multipicker/utils/CursorExtensions.kt
index 4618bd04d1..87cf48d0a7 100644
--- a/vector/src/main/java/im/vector/app/core/di/HasScreenInjector.kt
+++ b/multipicker/src/main/java/im/vector/lib/multipicker/utils/CursorExtensions.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019 New Vector Ltd
+ * Copyright (c) 2021 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package im.vector.app.core.di
+package im.vector.lib.multipicker.utils
 
-interface HasScreenInjector {
+import android.database.Cursor
 
-    fun injector(): ScreenComponent
+fun Cursor.getColumnIndexOrNull(column: String): Int? {
+    return getColumnIndex(column).takeIf { it != -1 }
 }
diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt
index 8f8625fe1c..b135954f63 100644
--- a/tools/check/forbidden_strings_in_code.txt
+++ b/tools/check/forbidden_strings_in_code.txt
@@ -160,7 +160,7 @@ Formatter\.formatShortFileSize===1
 # android\.text\.TextUtils
 
 ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
-enum class===106
+enum class===108
 
 ### Do not import temporary legacy classes
 import org.matrix.android.sdk.internal.legacy.riot===3
diff --git a/tools/emojis/emoji_picker_datasource_formatted.json b/tools/emojis/emoji_picker_datasource_formatted.json
index 4f3038d53c..341cdc0c54 100644
--- a/tools/emojis/emoji_picker_datasource_formatted.json
+++ b/tools/emojis/emoji_picker_datasource_formatted.json
@@ -4191,7 +4191,8 @@
                 "call",
                 "hand",
                 "hands",
-                "gesture"
+                "gesture",
+                "shaka"
             ]
         },
         "backhand-index-pointing-left": {
diff --git a/tools/release/pushPlayStoreMetaData.sh b/tools/release/pushPlayStoreMetaData.sh
index fe7cf7eca6..276ea32fce 100755
--- a/tools/release/pushPlayStoreMetaData.sh
+++ b/tools/release/pushPlayStoreMetaData.sh
@@ -68,15 +68,6 @@ else
   removeFullDes_th=1
 fi
 
-if [[ -f "./fastlane/metadata/android/vi/full_description.txt" ]]; then
-  echo "It appears that file ./fastlane/metadata/android/vi/full_description.txt now exists. This can be removed."
-  removeFullDes_vi=0
-else
-  echo "Copy default full description to ./fastlane/metadata/android/vi"
-  cp ./fastlane/metadata/android/en-US/full_description.txt ./fastlane/metadata/android/vi
-  removeFullDes_vi=1
-fi
-
 # Run fastlane
 echo "Run fastlane to push to the PlaysStore"
 fastlane deployMeta
@@ -103,8 +94,4 @@ if [[ ${removeFullDes_th} -eq 1 ]]; then
   rm ./fastlane/metadata/android/th/full_description.txt
 fi
 
-if [[ ${removeFullDes_vi} -eq 1 ]]; then
-  rm ./fastlane/metadata/android/vi/full_description.txt
-fi
-
 echo "Success!"
diff --git a/tools/release/sign_apk.sh b/tools/release/sign_apk.sh
index 7697f58ceb..aae9e1a378 100755
--- a/tools/release/sign_apk.sh
+++ b/tools/release/sign_apk.sh
@@ -17,7 +17,7 @@ PARAM_KEYSTORE_PATH=$1
 PARAM_APK=$2
 
 # Other params
-BUILD_TOOLS_VERSION="30.0.3"
+BUILD_TOOLS_VERSION="31.0.0-rc5"
 MIN_SDK_VERSION=21
 
 echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
diff --git a/tools/release/sign_apk_unsafe.sh b/tools/release/sign_apk_unsafe.sh
index af5b0f0e32..5d209a4a2b 100755
--- a/tools/release/sign_apk_unsafe.sh
+++ b/tools/release/sign_apk_unsafe.sh
@@ -23,7 +23,7 @@ PARAM_KS_PASS=$3
 PARAM_KEY_PASS=$4
 
 # Other params
-BUILD_TOOLS_VERSION="30.0.3"
+BUILD_TOOLS_VERSION="31.0.0-rc5"
 MIN_SDK_VERSION=21
 
 echo "Signing APK with build-tools version ${BUILD_TOOLS_VERSION} for min SDK version ${MIN_SDK_VERSION}..."
diff --git a/upstream_.github/ISSUE_TEMPLATE/bug.yml b/upstream_.github/ISSUE_TEMPLATE/bug.yml
index c1ab98e85d..c4eccd5b1f 100644
--- a/upstream_.github/ISSUE_TEMPLATE/bug.yml
+++ b/upstream_.github/ISSUE_TEMPLATE/bug.yml
@@ -23,7 +23,7 @@ body:
   - type: textarea
     id: result
     attributes:
-      label: Intended result and actual result
+      label: Outcome
       placeholder: Tell us what went wrong
       value: |
         #### What did you expect?
diff --git a/upstream_.github/ISSUE_TEMPLATE/enhancement.yml b/upstream_.github/ISSUE_TEMPLATE/enhancement.yml
index 5d9cfb3c88..71adce718e 100644
--- a/upstream_.github/ISSUE_TEMPLATE/enhancement.yml
+++ b/upstream_.github/ISSUE_TEMPLATE/enhancement.yml
@@ -10,7 +10,7 @@ body:
     id: usecase
     attributes:
       label: Your use case
-      description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups.
+      description: Please feel welcome to include screenshots or mock ups.
       placeholder: Tell us what you would like to do!
       value: |
         #### What would you like to do?
diff --git a/upstream_.github/dependabot.yml b/upstream_.github/dependabot.yml
index e552f5fd43..8c2f1041e0 100644
--- a/upstream_.github/dependabot.yml
+++ b/upstream_.github/dependabot.yml
@@ -18,6 +18,5 @@ updates:
     open-pull-requests-limit: 200
     reviewers:
       - "bmarty"
-###    ignore:
-###      - dependency-name: com.squareup.okhttp3:logging-interceptor
-###        versions: "> 3.12.10"
+    ignore:
+      - dependency-name: com.google.zxing:core
diff --git a/upstream_.github/workflows/sanity_test.yml b/upstream_.github/workflows/sanity_test.yml
index 3ab0017ce2..53b70276c5 100644
--- a/upstream_.github/workflows/sanity_test.yml
+++ b/upstream_.github/workflows/sanity_test.yml
@@ -1,9 +1,9 @@
 name: Sanity Test
 
 on:
-  pull_request: { }
-  push:
-    branches: [ main, develop ]
+  schedule:
+    # At 20:00 every day UTC
+    - cron: '0 20 * * *'
 
 # Enrich gradle.properties for CI/CD
 env:
@@ -14,13 +14,15 @@ env:
 jobs:
   integration-tests:
     name: Sanity Tests (Synapse)
-    runs-on: ubuntu-latest
+    runs-on: macos-latest
     strategy:
       fail-fast: false
       matrix:
-        api-level: [28]
+        api-level: [ 29 ]
     steps:
       - uses: actions/checkout@v2
+        with:
+          ref: develop
       - name: Set up Python 3.8
         uses: actions/setup-python@v2
         with:
@@ -46,11 +48,32 @@ jobs:
           python3 -m venv .synapse
           source .synapse/bin/activate
           pip install synapse matrix-synapse
-          curl -sL https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh --no-rate-limit \
-            | sed s/127.0.0.1/0.0.0.0/g | bash
+          curl -sL https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh \
+            | sed s/127.0.0.1/0.0.0.0/g | sed 's/http:\/\/localhost/http:\/\/10.0.2.2/g' | bash -s -- --no-rate-limit
+      - uses: actions/setup-java@v2
+        with:
+          distribution: 'adopt'
+          java-version: '11'
       - name: Run sanity tests on API ${{ matrix.api-level }}
         uses: reactivecircus/android-emulator-runner@v2
+        continue-on-error: true # allow pipeline to upload failure results
         with:
+          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
           api-level: ${{ matrix.api-level }}
-          script: ./gradlew $CI_GRADLE_ARG_PROPERTIES -PallWarningsAsErrors=false connectedGplayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=im.vector.app.ui.UiAllScreensSanityTest
+          emulator-build: 7425822  # workaround to emulator bug: https://github.com/ReactiveCircus/android-emulator-runner/issues/160
+          script: |
+            adb root
+            adb logcat -c
+            touch emulator.log
+            chmod 777 emulator.log
+            adb logcat >> emulator.log &
+            ./gradlew $CI_GRADLE_ARG_PROPERTIES -PallWarningsAsErrors=false connectedGplayDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=im.vector.app.ui.UiAllScreensSanityTest || adb pull storage/emulated/0/Pictures/failure_screenshots
 
+      - name: Upload Failing Test Report Log
+        if: failure()
+        uses: actions/upload-artifact@v2
+        with:
+          name: sanity-error-results
+          path: |
+            emulator.log
+            failure_screenshots/
diff --git a/upstream_.github/workflows/triage-incoming.yml b/upstream_.github/workflows/triage-incoming.yml
index 40d5507415..4ecc824424 100644
--- a/upstream_.github/workflows/triage-incoming.yml
+++ b/upstream_.github/workflows/triage-incoming.yml
@@ -8,7 +8,7 @@ jobs:
   automate-project-columns:
     runs-on: ubuntu-latest
     steps:
-      - uses: alex-page/github-project-automation-plus@v0.8.1
+      - uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
         with:
           project: Issue triage
           column: Incoming
diff --git a/upstream_.github/workflows/triage-move-labelled.yml b/upstream_.github/workflows/triage-move-labelled.yml
new file mode 100644
index 0000000000..f910cdf7ea
--- /dev/null
+++ b/upstream_.github/workflows/triage-move-labelled.yml
@@ -0,0 +1,124 @@
+name: Move labelled issues to correct boards and columns
+
+on:
+  issues:
+    types: [labeled]
+    
+jobs:
+  move_needs_info_issues:
+    name: Move X-Needs-Info issues to Need info on triage board
+    runs-on: ubuntu-latest
+    steps:
+      - uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338
+        with:
+          action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
+          project-url: "https://github.com/vector-im/element-android/projects/4"
+          column-name: "Need info"
+          label-name: "X-Needs-Info"
+
+  add_priority_design_issues_to_project:
+    name: Move priority X-Needs-Design issues to Design project board
+    runs-on: ubuntu-latest
+    if: >
+        contains(github.event.issue.labels.*.name, 'X-Needs-Design') &&
+        (contains(github.event.issue.labels.*.name, 'O-Frequent') ||
+         contains(github.event.issue.labels.*.name, 'O-Occasional')) &&
+        (contains(github.event.issue.labels.*.name, 'S-Critical') ||
+         contains(github.event.issue.labels.*.name, 'S-Major') ||
+         contains(github.event.issue.labels.*.name, 'S-Minor'))
+    steps:
+      - uses: octokit/graphql-action@v2.x
+        id: add_to_project
+        with:
+          headers: '{"GraphQL-Features": "projects_next_graphql"}'
+          query: |
+            mutation add_to_project($projectid:String!,$contentid:String!) {
+              addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
+                projectNextItem {
+                  id
+                }
+              }
+            }
+          projectid: ${{ env.PROJECT_ID }}
+          contentid: ${{ github.event.issue.node_id }}
+        env:
+          PROJECT_ID: "PN_kwDOAM0swc0sUA"
+          GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+
+  move_spaces_issues:
+    name: Move Spaces issues to Delight project board
+    runs-on: ubuntu-latest
+    if: >
+        contains(github.event.issue.labels.*.name, 'A-Spaces') ||
+        contains(github.event.issue.labels.*.name, 'A-Space-Settings') ||
+        contains(github.event.issue.labels.*.name, 'A-Subspaces')
+    steps:
+      - uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338
+        with:
+          action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
+          project-url: "https://github.com/orgs/vector-im/projects/6"
+          column-name: "📥 Inbox"
+          label-name: "A-Spaces"
+      - uses: octokit/graphql-action@v2.x
+        id: add_to_delight2
+        with:
+          headers: '{"GraphQL-Features": "projects_next_graphql"}'
+          query: |
+            mutation add_to_project($projectid:String!,$contentid:String!) {
+              addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
+                projectNextItem {
+                  id
+                }
+              }
+            }
+          projectid: ${{ env.PROJECT_ID }}
+          contentid: ${{ github.event.issue.node_id }}
+        env:
+          PROJECT_ID: "PN_kwDOAM0swc1HvQ"
+          GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+
+  move_voice-message_issues:
+    name: Move A-Voice Messages to Voice message board
+    runs-on: ubuntu-latest
+    if: >
+        contains(github.event.issue.labels.*.name, 'A-Voice Messages')
+    steps:
+      - uses: octokit/graphql-action@v2.x
+        with:
+          headers: '{"GraphQL-Features": "projects_next_graphql"}'
+          query: |
+            mutation add_to_project($projectid:String!,$contentid:String!) {
+              addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
+                projectNextItem {
+                  id
+                }
+              }
+            }
+          projectid: ${{ env.PROJECT_ID }}
+          contentid: ${{ github.event.issue.node_id }}
+        env:
+          PROJECT_ID: "PN_kwDOAM0swc2KCw"
+          GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+
+  move_threads_issues:
+    name: Move A-Threads to Thread board
+    runs-on: ubuntu-latest
+    if: >
+        contains(github.event.issue.labels.*.name, 'A-Threads')
+    steps:
+      - uses: octokit/graphql-action@v2.x
+        with:
+          headers: '{"GraphQL-Features": "projects_next_graphql"}'
+          query: |
+            mutation add_to_project($projectid:String!,$contentid:String!) {
+              addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
+                projectNextItem {
+                  id
+                }
+              }
+            }
+          projectid: ${{ env.PROJECT_ID }}
+          contentid: ${{ github.event.issue.node_id }}
+        env:
+          PROJECT_ID: "PN_kwDOAM0swc0rRA"
+          GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
diff --git a/upstream_.github/workflows/triage-move-unlabelled.yml b/upstream_.github/workflows/triage-move-unlabelled.yml
new file mode 100644
index 0000000000..94bd049b91
--- /dev/null
+++ b/upstream_.github/workflows/triage-move-unlabelled.yml
@@ -0,0 +1,35 @@
+name: Move unlabelled from needs info columns to triaged
+
+on:
+  issues:
+    types: [unlabeled]
+    
+jobs:
+  Move_Unabeled_Issue_On_Project_Board:
+    name: Move no longer X-Needs-Info issues to Triaged
+    runs-on: ubuntu-latest
+    if: >
+        ${{
+        !contains(github.event.issue.labels.*.name, 'X-Needs-Info') }}
+    env:
+      BOARD_NAME: "Issue triage"
+      OWNER: ${{ github.repository_owner }}
+      REPO: ${{ github.event.repository.name }}
+      ISSUE: ${{ github.event.issue.number }}
+    steps:
+      - name: Check if issue is already in "${{ env.BOARD_NAME }}"
+        run: |
+          if curl -i -H 'Content-Type: application/json' -H "Authorization: bearer ${{ secrets.GITHUB_TOKEN }}" -X POST -d '{"query": "query($issue: Int!, $owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issue(number: $issue) { projectCards { nodes { project { name } } } } } } ", "variables" : "{ \"issue\": '${ISSUE}', \"owner\": \"'${OWNER}'\", \"repo\": \"'${REPO}'\" }" }' https://api.github.com/graphql | grep "\b$BOARD_NAME\b"; then
+            echo "Issue is already in Project '$BOARD_NAME', proceeding";
+            echo "ALREADY_IN_BOARD=true" >> $GITHUB_ENV
+          else
+            echo "Issue is not in project '$BOARD_NAME', cancelling this workflow"
+            echo "ALREADY_IN_BOARD=false" >> $GITHUB_ENV
+          fi
+      - name: Move issue
+        uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
+        if: ${{ env.ALREADY_IN_BOARD == 'true' }}
+        with:
+          project: Issue triage
+          column: Triaged
+          repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
diff --git a/upstream_.github/workflows/triage-needs-info.yml b/upstream_.github/workflows/triage-needs-info.yml
deleted file mode 100644
index 64de7951c6..0000000000
--- a/upstream_.github/workflows/triage-needs-info.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: Move X-Needs-Info into Need info column in the Issue triage board
-
-on:
-  issues:
-    types: [labeled]
-    
-jobs:
-  Move_Labeled_Issue_On_Project_Board:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: konradpabjan/move-labeled-or-milestoned-issue@v2.0
-      with:
-        action-token: ${{ secrets.GITHUB_TOKEN }}
-        project-url: "https://github.com/vector-im/element-android/projects/4"
-        column-name: "Need info"
-        label-name: "X-Needs-Info"
diff --git a/upstream_.github/workflows/triage-priority-bugs.yml b/upstream_.github/workflows/triage-priority-bugs.yml
new file mode 100644
index 0000000000..018bb8bb55
--- /dev/null
+++ b/upstream_.github/workflows/triage-priority-bugs.yml
@@ -0,0 +1,55 @@
+name: Move P1 issues into the P1 column for the App Team and Crypto team
+
+on:
+  issues:
+    types: [labeled, unlabeled]
+
+jobs:
+  p1_issues_to_team_workboard:
+    runs-on: ubuntu-latest
+    if: >
+        (!contains(github.event.issue.labels.*.name, 'A-E2EE') &&
+         !contains(github.event.issue.labels.*.name, 'A-E2EE-Cross-Signing') &&
+         !contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') &&
+         !contains(github.event.issue.labels.*.name, 'A-E2EE-Key-Backup') &&
+         !contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification') &&
+         !contains(github.event.issue.labels.*.name, 'A-Spaces') &&
+         !contains(github.event.issue.labels.*.name, 'A-Spaces-Settings') &&
+         !contains(github.event.issue.labels.*.name, 'A-Subspaces')) &&
+        (contains(github.event.issue.labels.*.name, 'T-Defect') &&
+         contains(github.event.issue.labels.*.name, 'S-Critical') &&
+         (contains(github.event.issue.labels.*.name, 'O-Frequent') ||
+          contains(github.event.issue.labels.*.name, 'O-Occasional')) ||
+         contains(github.event.issue.labels.*.name, 'S-Major') &&
+         contains(github.event.issue.labels.*.name, 'O-Frequent') ||
+         contains(github.event.issue.labels.*.name, 'A11y') &&
+         contains(github.event.issue.labels.*.name, 'O-Frequent'))
+    steps:
+      - uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
+        with:
+          project: Android App Team
+          column: P1
+          repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
+
+  P1_issues_to_crypto_team_workboard:
+    runs-on: ubuntu-latest
+    if: >
+        (contains(github.event.issue.labels.*.name, 'A-E2EE') ||
+         contains(github.event.issue.labels.*.name, 'A-E2EE-Cross-Signing') ||
+         contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
+         contains(github.event.issue.labels.*.name, 'A-E2EE-Key-Backup') ||
+         contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification')) &&
+        (contains(github.event.issue.labels.*.name, 'T-Defect') &&
+         contains(github.event.issue.labels.*.name, 'S-Critical') &&
+         (contains(github.event.issue.labels.*.name, 'O-Frequent') ||
+          contains(github.event.issue.labels.*.name, 'O-Occasional')) ||
+         contains(github.event.issue.labels.*.name, 'S-Major') &&
+         contains(github.event.issue.labels.*.name, 'O-Frequent') ||
+         contains(github.event.issue.labels.*.name, 'A11y') &&
+         contains(github.event.issue.labels.*.name, 'O-Frequent'))
+    steps:
+      - uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
+        with:
+          project: Crypto Team
+          column: Ready
+          repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
diff --git a/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103040.txt b/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103040.txt
new file mode 100644
index 0000000000..ac909485d7
--- /dev/null
+++ b/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Přidání podpory přítomnosti pro místnost s přímými zprávami (poznámka: přítomnost je na matrix.org zakázána). Opět přidána podpora Android Auto.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103050.txt b/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103050.txt
new file mode 100644
index 0000000000..6aee9110ef
--- /dev/null
+++ b/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Přidání podpory přítomnosti pro místnost s přímými zprávami (poznámka: přítomnost je na matrix.org zakázána). Opět přidána podpora Android Auto.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103060.txt b/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103060.txt
new file mode 100644
index 0000000000..ef29377a46
--- /dev/null
+++ b/upstream_fastlane/metadata/android/cs-CZ/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Hlavní změny v této verzi: Přidání podpory přítomnosti pro místnost s přímými zprávami (poznámka: přítomnost je na matrix.org zakázána). Opět přidána podpora Android Auto.
+Úplný seznam změn: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/de-DE/changelogs/40103000.txt b/upstream_fastlane/metadata/android/de-DE/changelogs/40103000.txt
new file mode 100644
index 0000000000..85386226db
--- /dev/null
+++ b/upstream_fastlane/metadata/android/de-DE/changelogs/40103000.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Organisiere deine Räume mit Spaces!
+Alle Änderungen: https://github.com/vector-im/element-android/releases/tag/v1.3.0
diff --git a/upstream_fastlane/metadata/android/de-DE/changelogs/40103010.txt b/upstream_fastlane/metadata/android/de-DE/changelogs/40103010.txt
new file mode 100644
index 0000000000..3323a37a59
--- /dev/null
+++ b/upstream_fastlane/metadata/android/de-DE/changelogs/40103010.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Organisiere deine Räume mit Spaces, Crash aus 1.3.0 gefixt.
+Alle Änderungen: https://github.com/vector-im/element-android/releases/tag/v1.3.1
diff --git a/upstream_fastlane/metadata/android/de-DE/changelogs/40103020.txt b/upstream_fastlane/metadata/android/de-DE/changelogs/40103020.txt
new file mode 100644
index 0000000000..880ec71c4d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/de-DE/changelogs/40103020.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Unterstützung für Android Auto, Viele Fehlerbehebungen
+Alle Änderungen: https://github.com/vector-im/element-android/releases/tag/v1.3.2
diff --git a/upstream_fastlane/metadata/android/de-DE/changelogs/40103030.txt b/upstream_fastlane/metadata/android/de-DE/changelogs/40103030.txt
new file mode 100644
index 0000000000..da3451fb0d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/de-DE/changelogs/40103030.txt
@@ -0,0 +1,2 @@
+Hauptänderungen: Bedingungen des Identitätsservers in Einstellungen anzeigen. Unterstützung für Android Auto temporär entfernt.
+Alle Änderungen: https://github.com/vector-im/element-android/releases/tag/v1.3.3
diff --git a/upstream_fastlane/metadata/android/de-DE/changelogs/40103040.txt b/upstream_fastlane/metadata/android/de-DE/changelogs/40103040.txt
new file mode 100644
index 0000000000..37ab9ccd8f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/de-DE/changelogs/40103040.txt
@@ -0,0 +1,4 @@
+Hauptänderungen: 
+- Anwesenheiten in Direktnachrichten anzeigen (Momentan auf Matrix.org deaktiviert)
+- Android Auto wird wieder unterstützt
+Alle Änderungen: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/de-DE/full_description.txt b/upstream_fastlane/metadata/android/de-DE/full_description.txt
index 30eb153ee9..c4fecf7674 100644
--- a/upstream_fastlane/metadata/android/de-DE/full_description.txt
+++ b/upstream_fastlane/metadata/android/de-DE/full_description.txt
@@ -37,3 +37,6 @@ Kurznachrichten, Sprach- und Videoanrufe, Dateifreigaben, Bildschirmübertragung
 
 <b>Da Weitermachen, wo Sie aufgehört haben</b>
 Bleiben Sie in Kontakt, egal wo Sie sind, mit vollständig synchronisiertem Nachrichtenverlauf quer über all Ihre Geräte und im Netz auf https://app.element.io
+
+<b>Open source</b>
+Element ist ein Open-Source-Projekt und wird auf GitHub gehostet. Solltest du Fehler in Element finden, melde diese bitte hier: https://github.com/vector-im/element-android
diff --git a/upstream_fastlane/metadata/android/en-US/changelogs/40103070.txt b/upstream_fastlane/metadata/android/en-US/changelogs/40103070.txt
new file mode 100644
index 0000000000..9a7030728a
--- /dev/null
+++ b/upstream_fastlane/metadata/android/en-US/changelogs/40103070.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Bug fixes mainly regarding the notifications.
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.7-RC2
\ No newline at end of file
diff --git a/upstream_fastlane/metadata/android/en-US/changelogs/40103080.txt b/upstream_fastlane/metadata/android/en-US/changelogs/40103080.txt
new file mode 100644
index 0000000000..fc00c5da9e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/en-US/changelogs/40103080.txt
@@ -0,0 +1,2 @@
+Main changes in this version: Bug fixes!
+Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.3.8
\ No newline at end of file
diff --git a/upstream_fastlane/metadata/android/et/changelogs/40103040.txt b/upstream_fastlane/metadata/android/et/changelogs/40103040.txt
new file mode 100644
index 0000000000..2ede9de81e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/et/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: Lisasime otsevestlustele kasutaja võrguolekute toe (matrix.org puhul on välja lülitatud) ja uuesti lisasime Android Auto toe.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/et/changelogs/40103050.txt b/upstream_fastlane/metadata/android/et/changelogs/40103050.txt
new file mode 100644
index 0000000000..c68db70b6a
--- /dev/null
+++ b/upstream_fastlane/metadata/android/et/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: Lisasime otsevestlustele kasutaja võrguolekute toe (matrix.org puhul on välja lülitatud) ja uuesti lisasime Android Auto toe.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/et/changelogs/40103060.txt b/upstream_fastlane/metadata/android/et/changelogs/40103060.txt
new file mode 100644
index 0000000000..d1c44870fa
--- /dev/null
+++ b/upstream_fastlane/metadata/android/et/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Põhilised muutused selles versioonis: Lisasime otsevestlustele kasutaja võrguolekute toe (matrix.org puhul on välja lülitatud) ja uuesti lisasime Android Auto toe.
+Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/fa/changelogs/40103040.txt b/upstream_fastlane/metadata/android/fa/changelogs/40103040.txt
new file mode 100644
index 0000000000..5da14baf6e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/fa/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+تغییرات اصلی در این نگارش: افزودن پشتیبانی حضور برای اتاق پیام خصوصی (توجه: حضور روی matrix.org از کار افتاده است). افزودن دوبارهٔ پشتیبانی اندروید خودرو.
+گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/fr-FR/changelogs/40103040.txt b/upstream_fastlane/metadata/android/fr-FR/changelogs/40103040.txt
new file mode 100644
index 0000000000..7017fa243f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/fr-FR/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : ajout du support pour les indicateurs de présence, dans les conversations privées (attention : les indicateurs de présence sont désactivés sur matrix.org). Réactivation de la prise en charge de Android Auto.
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/fr-FR/changelogs/40103050.txt b/upstream_fastlane/metadata/android/fr-FR/changelogs/40103050.txt
new file mode 100644
index 0000000000..08143ead2f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/fr-FR/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : ajout du support pour les indicateurs de présence, dans les conversations privées (attention : les indicateurs de présence sont désactivés sur matrix.org). Réactivation de la prise en charge de Android Auto.
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/fr-FR/changelogs/40103060.txt b/upstream_fastlane/metadata/android/fr-FR/changelogs/40103060.txt
new file mode 100644
index 0000000000..0187c4bf88
--- /dev/null
+++ b/upstream_fastlane/metadata/android/fr-FR/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Principaux changements pour cette version : ajout du support pour les indicateurs de présence, dans les conversations privées (attention : les indicateurs de présence sont désactivés sur matrix.org). Réactivation de la prise en charge de Android Auto.
+Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/fy/short_description.txt b/upstream_fastlane/metadata/android/fy/short_description.txt
index ddc559b59c..f0f44ad06c 100644
--- a/upstream_fastlane/metadata/android/fy/short_description.txt
+++ b/upstream_fastlane/metadata/android/fy/short_description.txt
@@ -1 +1 @@
-Groepsberjochtetsjinst - fersifere berjochten, groeps petearen en fideo skilje
+Groepsberjochtetsjinst - fersifere berjochten, groepspetearen en fideobelje
diff --git a/upstream_fastlane/metadata/android/fy/title.txt b/upstream_fastlane/metadata/android/fy/title.txt
index c4b5b596fc..0c77d7d613 100644
--- a/upstream_fastlane/metadata/android/fy/title.txt
+++ b/upstream_fastlane/metadata/android/fy/title.txt
@@ -1 +1 @@
-Element - Feilige Berjochtetsjinst
+Element - Feilige berjochtetsjinst
diff --git a/upstream_fastlane/metadata/android/hu-HU/changelogs/40103040.txt b/upstream_fastlane/metadata/android/hu-HU/changelogs/40103040.txt
new file mode 100644
index 0000000000..de2e859028
--- /dev/null
+++ b/upstream_fastlane/metadata/android/hu-HU/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Állapot állítási lehetőség közvetlen beszélgetéseknél (megj.: a matrix.org-on az állapot jelzés ki van kapcsolva). Újra elérhető az Android Auto.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/hu-HU/changelogs/40103050.txt b/upstream_fastlane/metadata/android/hu-HU/changelogs/40103050.txt
new file mode 100644
index 0000000000..e46bf39f83
--- /dev/null
+++ b/upstream_fastlane/metadata/android/hu-HU/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Állapot állítási lehetőség közvetlen beszélgetéseknél (megj.: a matrix.org-on az állapot jelzés ki van kapcsolva). Újra elérhető az Android Auto.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/hu-HU/changelogs/40103060.txt b/upstream_fastlane/metadata/android/hu-HU/changelogs/40103060.txt
new file mode 100644
index 0000000000..1fc6ce5b8a
--- /dev/null
+++ b/upstream_fastlane/metadata/android/hu-HU/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Fő változás ebben a verzióban: Állapot állítási lehetőség közvetlen beszélgetéseknél (megj.: a matrix.org-on az állapot jelzés ki van kapcsolva). Újra elérhető az Android Auto.
+Teljes változásnapló: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/id/changelogs/40103040.txt b/upstream_fastlane/metadata/android/id/changelogs/40103040.txt
new file mode 100644
index 0000000000..0641f72ffd
--- /dev/null
+++ b/upstream_fastlane/metadata/android/id/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Perubahan utama di versi ini: Tambahkan dukungan presensi, untuk ruangan Pesan Langsung (diingat bahwa presensi dinonaktifkan di matrix.org). Tambahkan lagi dukungan Android Auto.
+Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/id/changelogs/40103050.txt b/upstream_fastlane/metadata/android/id/changelogs/40103050.txt
new file mode 100644
index 0000000000..ec7c9423bf
--- /dev/null
+++ b/upstream_fastlane/metadata/android/id/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Tambahkan dukungan presensi, untuk ruangan Pesan Langsung (diingat bahwa presensi dinonaktifkan di matrix.org). Tambahkan lagi dukungan Android Auto.
+Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/id/changelogs/40103060.txt b/upstream_fastlane/metadata/android/id/changelogs/40103060.txt
new file mode 100644
index 0000000000..4265699d2f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/id/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Perubahan utama dalam versi ini: Tambahkan dukungan presensi, untuk ruangan Pesan Langsung (catatan: presensi dinonaktifkan di matrix.org). Tambahkan lagi dukungan Android Auto.
+Changelog lanjutan: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/id/full_description.txt b/upstream_fastlane/metadata/android/id/full_description.txt
index dfa9c8c826..d28ae8b004 100644
--- a/upstream_fastlane/metadata/android/id/full_description.txt
+++ b/upstream_fastlane/metadata/android/id/full_description.txt
@@ -1,42 +1,42 @@
-Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi obrolan ini menggunakan enkripsi ujung-ke-ujung untuk memberikan konferensi video, berbagi file, dan panggilan suara.
+Element adalah perpesanan yang aman dan aplikasi kolaborasi tim produktivitas yang ideal untuk obrolan grup saat bekerja jarak jauh. Aplikasi perpesanan ini menggunakan enkripsi ujung-ke-ujung untuk memberikan konferensi video, pembagian file, dan panggilan suara yang aman.
 
-<b>Fitur Element termasuk:</b>
+<b>Fitur Element termasuk</b>
 - Alat komunikasi online yang canggih
-- Pesan terenkripsi sepenuhnya untuk memungkinkan komunikasi perusahaan yang lebih aman, bahkan untuk pekerja jarak jauh
-- Obrolan terdesentralisasi berdasarkan framework sumber-terbuka Matrix
-- Berbagi file dengan aman dengan data terenkripsi saat mengelola proyek
-- Obrolan video dengan VoIP dan berbagi layar
+- Pesan-pesan yang dienkripsi sepenuhnya untuk memungkinkan komunikasi perusahaan yang lebih aman, bahkan untuk pekerja jarak jauh
+- Obrolan terdesentralisasi berdasarkan kerangka Matrix yang sumber terbuka
+- Pembagian file aman dengan data terenkripsi saat mengelola proyek
+- Obrolan video dengan VoIP dan pembagian layar
 - Integrasi yang mudah dengan alat kolaborasi online favorit Anda, alat manajemen proyek, layanan VoIP dan aplikasi perpesanan tim lainnya
 
-Element benar-benar berbeda dari aplikasi perpesanan dan kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi terdesentralisasi. Matrix memungkinkan hosting sendiri untuk memberi pengguna kepemilikan maksimum dan kontrol data dan pesan mereka.
+Element benar-benar berbeda dari aplikasi perpesanan dan aplikasi kolaborasi lainnya. Element beroperasi pada Matrix, jaringan terbuka untuk pengiriman pesan yang aman dan komunikasi terdesentralisasi.
 
-<b>Pesan privasi dan terenkripsi</b>
-Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu melalui enkripsi ujung-ke-ujung dan verifikasi perangkat yang ditandatangani secara silang.
+<b>Perpesanan dengan privasi dan enkripsi</b>
+Element melindungi Anda dari iklan yang tidak diinginkan, penambangan data dan taman berdinding. Element juga mengamankan semua data Anda, komunikasi video dan suara satu-ke-satu dengan enkripsi ujung-ke-ujung dan verifikasi perangkat menggunakan penandatanganan silang.
 
-Element memberi Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan aman dengan siapa pun di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan dengan aplikasi seperti Slack.
+Element memberikan Anda kendali atas privasi Anda sambil memungkinkan Anda untuk berkomunikasi dengan siapa saja secara aman di jaringan Matrix, atau alat kolaborasi bisnis lainnya dengan mengintegrasikan aplikasi-aplikasi seperti Slack.
 
 <b>Element dapat dihost sendiri</b>
-Untuk memungkinkan lebih banyak kendali atas data dan percakapan sensitif Anda, Element bisa dihost sendiri atau Anda dapat memilih host berbasis Matrix - standar untuk komunikasi terdesentralisasi sumber-terbuka. Element memberi Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi.
+Untuk memungkinkan lebih banyak kendali atas data dan pesan-pesan sensitif Anda, Element dapat dihost sendiri atau Anda dapat memilih host berbasis Matrix, standar untuk komunikasi terdesentralisasi sumber terbuka. Element memberi Anda privasi, kepatuhan keamanan, dan fleksibilitas integrasi.
 
 <b>Miliki data Anda</b>
-Anda memutuskan di mana menyimpan data dan pesan Anda. Tanpa risiko penambangan data atau akses dari pihak ketiga.
+Anda memutuskan di mana untuk menyimpan data dan pesan-pesan Anda, tanpa risiko penambangan data atau akses dari pihak ketiga.
 
 Element menempatkan Anda dalam kendali dengan cara yang berbeda:
 1. Dapatkan akun gratis pada server publik matrix.org yang dihost oleh pengembang Matrix, atau memilih dari ribuan server publik yang dihost oleh sukarelawan
 2. Host sendiri akun Anda dengan menjalankan server pada infrastruktur IT Anda sendiri
-3. Daftar untuk akun di server khusus dengan hanya berlangganan platform hosting Element Matrix Services
+3. Daftar untuk akun di server khusus dengan berlangganan platform hosting Layanan Matrix Element
 
 <b>Pesan terbuka dan kolaborasi</b>
-Anda dapat mengobrol dengan siapa saja di jaringan Matrix, apakah mereka menggunakan Element, aplikasi Matrix lain atau bahkan jika mereka menggunakan aplikasi perpesanan yang berbeda.
+Anda dapat mengobrol dengan siapa saja di jaringan Matrix, jika mereka menggunakan Element, aplikasi Matrix lain atau bahkan menggunakan aplikasi perpesanan yang berbeda.
 
 <b>Sangat aman</b>
-Enkripsi ujung-ke-ujung yang nyata (hanya mereka yang dalam percakapan dapat mendekripsi pesan), dan verifikasi perangkat menggunakan penandatanganan-silang.
+Enkripsi ujung-ke-ujung yang nyata (hanya mereka yang dalam obrolan dapat mendekripsi pesan), dan verifikasi perangkat menggunakan penandatanganan silang.
 
 <b>Komunikasi dan integrasi lengkap</b>
-Perpesanan, panggilan suara dan video, berbagi file, berbagi layar dan banyak integrasi, bot dan widget. Buat ruangan, komunitas, tetap terhubung dan selesaikan hal-hal.
+Perpesanan, panggilan suara dan video, pembagian file, pembagian layar dan banyak integrasi bot dan widget. Buat ruangan dan komunitas, tetap terhubung dan selesaikan hal-hal penting.
 
 <b>Ambil di mana Anda tinggalkan</b>
-Tetap terhubung di mana pun Anda berada dengan riwayat pesan yang sepenuhnya disinkronkan di semua perangkat Anda dan di web di https://app.element.io
+Tetap terhubung di mana Anda berada, dengan riwayat pesan yang disinkronkan di semua perangkat Anda dan web di https://app.element.io
 
-<b>Open source</b>
-Element Android adalah proyek sumber terbuka, di-host oleh GitHub. Silakan melaporkan bug dan/atau membuat kontribusi ke pengembangannya di https://github.com/vector-im/element-android
+<b>Sumber terbuka</b>
+Element Android adalah proyek sumber terbuka, dihost oleh GitHub. Silakan laporkan masalah yang Anda temukan, atau membuat kontribusi ke pengembangannya di https://github.com/vector-im/element-android
diff --git a/upstream_fastlane/metadata/android/id/short_description.txt b/upstream_fastlane/metadata/android/id/short_description.txt
index e6c3a2f7a9..1cd770dd73 100644
--- a/upstream_fastlane/metadata/android/id/short_description.txt
+++ b/upstream_fastlane/metadata/android/id/short_description.txt
@@ -1 +1 @@
-Perpesanan grup - pesan terenkripsi, panggilan grup dan video
+Perpesanan grup - perpesanan, panggilan suara dan video grup terenkripsi
diff --git a/upstream_fastlane/metadata/android/it-IT/changelogs/40103040.txt b/upstream_fastlane/metadata/android/it-IT/changelogs/40103040.txt
new file mode 100644
index 0000000000..e28ce08e03
--- /dev/null
+++ b/upstream_fastlane/metadata/android/it-IT/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: aggiunto supporto alla presenza per messaggi diretti (nota: la presenza è disattivata su matrix.org). Aggiunto di nuovo il supporto ad Android Auto.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/it-IT/changelogs/40103050.txt b/upstream_fastlane/metadata/android/it-IT/changelogs/40103050.txt
new file mode 100644
index 0000000000..2762949682
--- /dev/null
+++ b/upstream_fastlane/metadata/android/it-IT/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: aggiunto supporto alla presenza per messaggi diretti (nota: la presenza è disattivata su matrix.org). Aggiunto di nuovo il supporto ad Android Auto.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/it-IT/changelogs/40103060.txt b/upstream_fastlane/metadata/android/it-IT/changelogs/40103060.txt
new file mode 100644
index 0000000000..f241fa9e57
--- /dev/null
+++ b/upstream_fastlane/metadata/android/it-IT/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Modifiche principali in questa versione: aggiunto supporto alla presenza per i messaggi diretti (nota: la presenza è disattivata su matrix.org). Aggiunto di nuovo il supporto a Android Auto.
+Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/pt-BR/changelogs/40103040.txt b/upstream_fastlane/metadata/android/pt-BR/changelogs/40103040.txt
new file mode 100644
index 0000000000..b713e0418f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/pt-BR/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Adicionar suporte a Presença, para sala de Mensagem Direta (nota: presença está desabilitada em matrix.org). Adicionar de novo suporte a Android Auto.
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/pt-BR/changelogs/40103050.txt b/upstream_fastlane/metadata/android/pt-BR/changelogs/40103050.txt
new file mode 100644
index 0000000000..e565d269ed
--- /dev/null
+++ b/upstream_fastlane/metadata/android/pt-BR/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Adicionar suporte a Presença, para sala de Mensagem Direta (nota: presença está desabilitada em matrix.org). Adicionar de novo suporte a Android Auto.
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/pt-BR/changelogs/40103060.txt b/upstream_fastlane/metadata/android/pt-BR/changelogs/40103060.txt
new file mode 100644
index 0000000000..b246759d26
--- /dev/null
+++ b/upstream_fastlane/metadata/android/pt-BR/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Principais mudanças nesta versão: Adicionar suporte a Presença, para sala de Mensagem Direta (nota: presença está desabilitada em matrix.org). Adicionar de novo suporte a Android Auto.
+Changelog completo: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/ru-RU/changelogs/40103040.txt b/upstream_fastlane/metadata/android/ru-RU/changelogs/40103040.txt
new file mode 100644
index 0000000000..e4e5edc5b1
--- /dev/null
+++ b/upstream_fastlane/metadata/android/ru-RU/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Основные изменения в этой версии: Добавлена поддержка присутствия, для комнат личных сообщений (примечание: присутствие отключено на matrix.org). Снова добавлена поддержка Android Auto.
+Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/sq/changelogs/40103040.txt b/upstream_fastlane/metadata/android/sq/changelogs/40103040.txt
new file mode 100644
index 0000000000..6ad044b6a4
--- /dev/null
+++ b/upstream_fastlane/metadata/android/sq/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Ndryshimet kryesore në këtë version: Shtim mbulimi për Prani, për dhomë Mesazh i Drejtpërdrejtë (shënim: në matrix.org prania është e çaktivizuar). Shtim sërish i mbulimit për Android Auto.
+Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/sq/changelogs/40103050.txt b/upstream_fastlane/metadata/android/sq/changelogs/40103050.txt
new file mode 100644
index 0000000000..bb609da987
--- /dev/null
+++ b/upstream_fastlane/metadata/android/sq/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Ndryshimet kryesore në këtë version: Shtim mbulimi për Prani, për dhomën Mesazh i Drejtpërdrejtë (shënim: prania është e çaktivizuar në matrix.org). Shtim sërish i mbulimit për Android Auto.
+Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/sq/changelogs/40103060.txt b/upstream_fastlane/metadata/android/sq/changelogs/40103060.txt
new file mode 100644
index 0000000000..96afd47a5d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/sq/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Ndryshimet kryesore në këtë version: Shtim mbulimi për Prani, për dhomën Mesazh i Drejtpërdrejtë (shënim: prania është e çaktivizuar në matrix.org). Shtim sërish i mbulimit për Android Auto.
+Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/sv-SE/changelogs/40103040.txt b/upstream_fastlane/metadata/android/sv-SE/changelogs/40103040.txt
new file mode 100644
index 0000000000..faec3bef4d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/sv-SE/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Lägg till närvarostöd för direktmeddelanden (obs: närvaro är inaktiverat på matrix.org). Lägg till stöd för Android Auto igen.
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/sv-SE/changelogs/40103050.txt b/upstream_fastlane/metadata/android/sv-SE/changelogs/40103050.txt
new file mode 100644
index 0000000000..57ee7189e3
--- /dev/null
+++ b/upstream_fastlane/metadata/android/sv-SE/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Lägg till närvarostöd för direktmeddelanden (obs: närvaro är inaktiverat på matrix.org). Lägg till stöd för Android Auto igen.
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/sv-SE/changelogs/40103060.txt b/upstream_fastlane/metadata/android/sv-SE/changelogs/40103060.txt
new file mode 100644
index 0000000000..bac3775a2a
--- /dev/null
+++ b/upstream_fastlane/metadata/android/sv-SE/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Huvudsakliga ändringar i den här versionen: Lägg till närvarostöd för direktmeddelanden (obs: närvaro är inaktiverat på matrix.org). Lägg till stöd för Android Auto igen.
+Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/uk/changelogs/40103040.txt b/upstream_fastlane/metadata/android/uk/changelogs/40103040.txt
new file mode 100644
index 0000000000..b6d237241b
--- /dev/null
+++ b/upstream_fastlane/metadata/android/uk/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Основні зміни в цій версії: Додано підтримку присутності для кімнати особистих повідомлень (примітка: присутність вимкнено на matrix.org). Знову додано підтримку Android Auto.
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/uk/changelogs/40103050.txt b/upstream_fastlane/metadata/android/uk/changelogs/40103050.txt
new file mode 100644
index 0000000000..846d1a2d84
--- /dev/null
+++ b/upstream_fastlane/metadata/android/uk/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+Основні зміни у цій версії: Додано підтримку присутності для кімнати особистих повідомлень (примітка: присутність вимкнена на matrix.org). Знову додано підтримку Android Auto.
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/uk/changelogs/40103060.txt b/upstream_fastlane/metadata/android/uk/changelogs/40103060.txt
new file mode 100644
index 0000000000..a1eec4d4de
--- /dev/null
+++ b/upstream_fastlane/metadata/android/uk/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+Основні зміни у цій версії: Додано підтримку присутності для кімнати особистих повідомлень (примітка: присутність вимкнена на matrix.org). Знову додано підтримку Android Auto.
+Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40100120.txt b/upstream_fastlane/metadata/android/vi/changelogs/40100120.txt
new file mode 100644
index 0000000000..28c983ef2c
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40100120.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: xem trước URL, bàn phím Emoji mới, các khả năng cài đặt phòng mới và tuyết cho Giáng Sinh!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.0.12
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40100130.txt b/upstream_fastlane/metadata/android/vi/changelogs/40100130.txt
new file mode 100644
index 0000000000..baf756a7be
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40100130.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: xem trước URL, bàn phím Emoji mới, các khả năng cài đặt phòng mới và tuyết cho Giáng Sinh!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.0.13
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40100140.txt b/upstream_fastlane/metadata/android/vi/changelogs/40100140.txt
new file mode 100644
index 0000000000..83617e28a3
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40100140.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: chỉnh sửa quyền phòng, chủ đề Sáng/Tối tự động, và một loạt các bản sửa lỗi.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.0.14
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40100150.txt b/upstream_fastlane/metadata/android/vi/changelogs/40100150.txt
new file mode 100644
index 0000000000..b24be2665e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40100150.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: hỗ trợ đăng nhập từ mạng xã hội.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.0.15
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40100160.txt b/upstream_fastlane/metadata/android/vi/changelogs/40100160.txt
new file mode 100644
index 0000000000..3602b769ed
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40100160.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: hỗ trợ đăng nhập từ mạng xã hội.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.0.15 và https://github.com/vector-im/element-android/releases/tag/v1.0.16
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40100170.txt b/upstream_fastlane/metadata/android/vi/changelogs/40100170.txt
new file mode 100644
index 0000000000..40bb26719e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40100170.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Sửa lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.0.17
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101000.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101000.txt
new file mode 100644
index 0000000000..7c89b1b7ee
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101000.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cải tiến VoIP (các cuộc gọi thoại và video trong Tin nhắn Trực tiếp) và sửa lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.0
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101010.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101010.txt
new file mode 100644
index 0000000000..08b4dbf65c
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101010.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cải thiện hiệu suất và sửa lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.1
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101020.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101020.txt
new file mode 100644
index 0000000000..7bdfe395e8
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101020.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cải thiện hiệu suất và sửa lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.2
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101030.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101030.txt
new file mode 100644
index 0000000000..b058f5265f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101030.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cải thiện hiệu suất và sửa lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.3
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101040.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101040.txt
new file mode 100644
index 0000000000..30a5a009b1
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101040.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cải thiện hiệu suất và sửa lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.4
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101050.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101050.txt
new file mode 100644
index 0000000000..01de425aa6
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101050.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: sửa lỗi nhanh cho 1.1.4
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.5
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101060.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101060.txt
new file mode 100644
index 0000000000..887cc07d8e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101060.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: sửa lỗi nhanh cho 1.1.5
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.6
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101070.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101070.txt
new file mode 100644
index 0000000000..64441edcc6
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101070.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: hỗ trợ beta cho Space. Nén video trước khi gửi.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.7
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101080.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101080.txt
new file mode 100644
index 0000000000..2584b0c156
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101080.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Cải tiến cho Space.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.8
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101090.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101090.txt
new file mode 100644
index 0000000000..ebf2c0f141
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101090.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: thêm hỗ trợ cho mạng gitter.im.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.9
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101100.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101100.txt
new file mode 100644
index 0000000000..ba62ad1c9f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101100.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cập nhật chủ đề và phong cách và các tính năng mới cho Space.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.10
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101110.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101110.txt
new file mode 100644
index 0000000000..07fce22a35
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101110.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cập nhật chủ đề và phong cách và các tính năng mới cho Space (sửa lỗi cho 1.1.1.0)
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.11
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101120.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101120.txt
new file mode 100644
index 0000000000..fddcd9656e
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101120.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: cập nhật chủ đề và phong cách và sửa lỗi sau khi gọi video
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.12
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101130.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101130.txt
new file mode 100644
index 0000000000..003154de91
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101130.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: chủ yếu là sự ổn định và cập nhật sửa lỗi.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.13
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101140.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101140.txt
new file mode 100644
index 0000000000..b247be0ce3
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101140.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: sửa lỗi các tin nhắn mã hóa.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.14
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101150.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101150.txt
new file mode 100644
index 0000000000..28d6523ffb
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101150.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: triển khai tin nhắn thoại trong cài đặt thí nghiệm.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.15
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40101160.txt b/upstream_fastlane/metadata/android/vi/changelogs/40101160.txt
new file mode 100644
index 0000000000..4ff2c813dc
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40101160.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Sửa lỗi gửi tin nhắn mã hóa khi có ai đó trong phòng đăng xuất.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.1.16
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40102000.txt b/upstream_fastlane/metadata/android/vi/changelogs/40102000.txt
new file mode 100644
index 0000000000..067d8c5705
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40102000.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Tin nhắn Thoại được bật mặc định.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.2.0
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40102010.txt b/upstream_fastlane/metadata/android/vi/changelogs/40102010.txt
new file mode 100644
index 0000000000..3e71d31446
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40102010.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Nhiều cải tiến trong VoIP và Space (vẫn đang trong beta).
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.2.1
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40103000.txt b/upstream_fastlane/metadata/android/vi/changelogs/40103000.txt
new file mode 100644
index 0000000000..1bbfba8f38
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40103000.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Sắp xếp các phòng của bạn bằng Space!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.0
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40103010.txt b/upstream_fastlane/metadata/android/vi/changelogs/40103010.txt
new file mode 100644
index 0000000000..d3995343c4
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40103010.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Sắp xếp các phòng của bạn bằng Space! V1.3.1 khắc phục sự cố có thể xảy ra ở v1.3.0
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.1
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40103020.txt b/upstream_fastlane/metadata/android/vi/changelogs/40103020.txt
new file mode 100644
index 0000000000..33a81f4a5d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40103020.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Thêm hỗ trợ Android Auto. Sửa rất nhiều lỗi!
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.2
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40103030.txt b/upstream_fastlane/metadata/android/vi/changelogs/40103030.txt
new file mode 100644
index 0000000000..a36a3bb46d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40103030.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Hiển thị (các) chính sách máy chủ xác thực trong phần cài đặt. Tạm thời bỏ hỗ trợ Android Auto.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.3
diff --git a/upstream_fastlane/metadata/android/vi/changelogs/40103040.txt b/upstream_fastlane/metadata/android/vi/changelogs/40103040.txt
new file mode 100644
index 0000000000..aadb92827d
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+Những thay đổi chính trong phiên bản này: Thêm hỗ trợ hiển thị, cho phòng Tin nhắn Trực tiếp (lưu ý: hiển thị bị vô hiệu hóa trên matrix.org. Thêm hỗ trợ Android Auto trở lại.
+Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/vi/full_description.txt b/upstream_fastlane/metadata/android/vi/full_description.txt
new file mode 100644
index 0000000000..6bccb64fd5
--- /dev/null
+++ b/upstream_fastlane/metadata/android/vi/full_description.txt
@@ -0,0 +1,42 @@
+Element vừa là một ứng dụng nhắn tin an toàn vừa là một ứng dụng cộng tác nhóm năng suất, lý tưởng cho các cuộc trò chuyện nhóm trong khi làm việc từ xa. Ứng dụng trò chuyện này sử dụng mã hóa đầu cuối để cung cấp tính năng hội nghị truyền hình, chia sẻ tệp và cuộc gọi thoại mạnh mẽ.
+
+<b> Các tính năng của Element bao gồm: </b>
+- Các công cụ giao tiếp trực tuyến tiên tiến
+- Các tin nhắn được mã hóa hoàn toàn để cho phép liên lạc doanh nghiệp an toàn hơn, ngay cả đối với những người làm việc từ xa
+- Trò chuyện phi tập trung dựa trên khung mã nguồn mở Matrix
+- Chia sẻ tệp một cách an toàn với dữ liệu được mã hóa trong khi quản lý dự án
+- Trò chuyện video với VoIP và chia sẻ màn hình
+- Tích hợp dễ dàng với các công cụ cộng tác trực tuyến yêu thích của bạn, công cụ quản lý dự án, dịch vụ VoIP và các ứng dụng nhắn tin nhóm khác
+
+Element hoàn toàn khác với các ứng dụng nhắn tin và cộng tác khác. Nó hoạt động trên Matrix, một mạng mở để nhắn tin bảo mật và giao tiếp phi tập trung. Nó cho phép tự lưu trữ để cung cấp cho người dùng quyền sở hữu và kiểm soát tối đa dữ liệu và tin nhắn của họ.
+
+<b> Nhắn tin mã hóa và riêng tư </b>
+Element bảo vệ bạn khỏi các quảng cáo không mong muốn, khai thác dữ liệu và khu vườn có tường bao quanh. Nó cũng bảo mật tất cả dữ liệu của bạn, video 1-1 và giao tiếp thoại thông qua mã hóa đầu cuối và xác minh thiết bị có chữ ký chéo.
+
+Element cung cấp cho bạn quyền kiểm soát quyền riêng tư của mình đồng thời cho phép bạn giao tiếp an toàn với bất kỳ ai trên mạng Ma trận hoặc các công cụ cộng tác kinh doanh khác bằng cách tích hợp với các ứng dụng như Slack.
+
+<b> Phần tử có thể được tự lưu trữ </b>
+Để cho phép kiểm soát nhiều hơn dữ liệu nhạy cảm và các cuộc trò chuyện của bạn, Element có thể được tự host hoặc bạn có thể chọn bất kỳ host Matrix nào - tiêu chuẩn cho giao tiếp phân tán, mã nguồn mở. Element cung cấp cho bạn quyền riêng tư, tuân thủ bảo mật và tính linh hoạt trong tích hợp.
+
+<b> Sở hữu dữ liệu của bạn </b>
+Bạn quyết định nơi lưu giữ dữ liệu và tin nhắn của mình. Không có rủi ro khai thác dữ liệu hoặc truy cập từ bên thứ ba.
+
+Element giúp bạn kiểm soát theo những cách khác nhau:
+1. Nhận một tài khoản miễn phí trên máy chủ công cộng matrix.org do các nhà phát triển Matrix host hoặc chọn từ hàng nghìn máy chủ công cộng do các tình nguyện viên lưu trữ
+2. Tự host tài khoản của bạn bằng cách chạy một máy chủ trên cơ sở hạ tầng CNTT của riêng bạn
+3. Đăng ký tài khoản trên máy chủ tùy chỉnh bằng cách chỉ cần đăng ký nền tảng Element Matrix Services hosting
+
+<b> Mở tin nhắn và cộng tác </b>
+Bạn có thể trò chuyện với bất kỳ ai trên mạng Matrix, cho dù họ đang sử dụng Element, một ứng dụng Matrix khác hay ngay cả khi họ đang sử dụng một ứng dụng nhắn tin khác.
+
+<b> Siêu bảo mật </b>
+Mã hóa đầu-cuối thực (chỉ những người trong cuộc trò chuyện mới có thể giải mã tin nhắn) và xác minh thiết bị xác thực chéo.
+
+<b> Giao tiếp và tích hợp hoàn chỉnh </b>
+Nhắn tin, cuộc gọi thoại và video, chia sẻ tệp, chia sẻ màn hình và một loạt các tích hợp, bot và widget. Xây dựng phòng, cộng đồng, giữ liên lạc và hoàn thành công việc.
+
+<b> Tiếp tục nơi bạn đã dừng lại </b>
+Giữ liên lạc mọi lúc mọi nơi với lịch sử tin nhắn được đồng bộ hóa hoàn toàn trên tất cả các thiết bị của bạn và trên web tại https://app.element.io
+
+<b> Mã nguồn mở </b>
+Element Android là một dự án mã nguồn mở, được host bởi GitHub. Vui lòng báo cáo lỗi và / hoặc đóng góp vào sự phát triển của nó tại https://github.com/vector-im/element-android
diff --git a/upstream_fastlane/metadata/android/zh-CN/changelogs/40103040.txt b/upstream_fastlane/metadata/android/zh-CN/changelogs/40103040.txt
new file mode 100644
index 0000000000..c879c3d036
--- /dev/null
+++ b/upstream_fastlane/metadata/android/zh-CN/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+此版本主要变化:为 Direct Message 聊天室添加 Presence 支持 (注意:presence 在 matrix.org 上是禁用的)。再次添加 Android Auto 支持。
+完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/zh-CN/changelogs/40103050.txt b/upstream_fastlane/metadata/android/zh-CN/changelogs/40103050.txt
new file mode 100644
index 0000000000..7343ae0b9f
--- /dev/null
+++ b/upstream_fastlane/metadata/android/zh-CN/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:为私信聊天室添加 Presence 支持 (注意:在 matrix.org 上 Presence 是禁用的)。再次添加 Android Auto 支持。
+完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/zh-CN/changelogs/40103060.txt b/upstream_fastlane/metadata/android/zh-CN/changelogs/40103060.txt
new file mode 100644
index 0000000000..8322539927
--- /dev/null
+++ b/upstream_fastlane/metadata/android/zh-CN/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+此版本的主要变化:为私信聊天室添加 Presence 支持(注意:在 matrix.org 上 Presence 是禁用的)。再次添加 Android Auto 支持。
+完整更新日志:https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/upstream_fastlane/metadata/android/zh-TW/changelogs/40103040.txt b/upstream_fastlane/metadata/android/zh-TW/changelogs/40103040.txt
new file mode 100644
index 0000000000..bd82b54e45
--- /dev/null
+++ b/upstream_fastlane/metadata/android/zh-TW/changelogs/40103040.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:為直接訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。加回 Android Auto 支援。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.4
diff --git a/upstream_fastlane/metadata/android/zh-TW/changelogs/40103050.txt b/upstream_fastlane/metadata/android/zh-TW/changelogs/40103050.txt
new file mode 100644
index 0000000000..659be479f5
--- /dev/null
+++ b/upstream_fastlane/metadata/android/zh-TW/changelogs/40103050.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:為直接訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。加回 Android Auto 支援。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.5
diff --git a/upstream_fastlane/metadata/android/zh-TW/changelogs/40103060.txt b/upstream_fastlane/metadata/android/zh-TW/changelogs/40103060.txt
new file mode 100644
index 0000000000..e1223a40e5
--- /dev/null
+++ b/upstream_fastlane/metadata/android/zh-TW/changelogs/40103060.txt
@@ -0,0 +1,2 @@
+此版本中的主要變動:為直接訊息聊天室新增 Presence 支援(請注意:此功能在 matrix.org 上停用)。加回 Android Auto 支援。
+完整的變更紀錄:https://github.com/vector-im/element-android/releases/tag/v1.3.6
diff --git a/vector/build.gradle b/vector/build.gradle
index 7e4cc18795..a1d5a47bae 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -6,6 +6,7 @@ apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-parcelize'
 apply plugin: 'kotlin-kapt'
 apply plugin: 'placeholder-resolver'
+apply plugin: 'dagger.hilt.android.plugin'
 
 kapt {
     correctErrorTypes = true
@@ -14,7 +15,7 @@ kapt {
 // Note: 2 digits max for each value
 ext.versionMajor = 1
 ext.versionMinor = 3
-ext.versionPatch = 6
+ext.versionPatch = 8
 
 ext.scVersion = 46
 
@@ -106,7 +107,6 @@ def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0
 android {
 
 
-
     // Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use
     // Ref: https://issuetracker.google.com/issues/144111441
     ndkVersion "21.3.6528147"
@@ -214,6 +214,7 @@ android {
         // This property does not affect tests that you run using Android Studio.”
         animationsDisabled = true
 
+        // Comment to run on Android 12
         execution 'ANDROIDX_TEST_ORCHESTRATOR'
     }
 
@@ -341,7 +342,6 @@ configurations {
 dependencies {
 
     implementation project(":matrix-sdk-android")
-    implementation project(":matrix-sdk-android-rx")
     implementation project(":matrix-sdk-android-flow")
     implementation project(":diff-match-patch")
     implementation project(":multipicker")
@@ -368,8 +368,10 @@ dependencies {
     implementation libs.squareup.moshi
     implementation libs.squareup.moshiKt
     kapt libs.squareup.moshiKotlin
-    implementation libs.androidx.lifecycleExtensions
+
+    // Lifecycle
     implementation libs.androidx.lifecycleLivedata
+    implementation libs.androidx.lifecycleProcess
 
     implementation libs.androidx.datastore
     implementation libs.androidx.datastorepreferences
@@ -382,25 +384,18 @@ dependencies {
     implementation 'com.facebook.stetho:stetho:1.6.0'
 
     // Phone number https://github.com/google/libphonenumber
-    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.35'
+    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.37'
 
-    // rx
-    implementation libs.rx.rxKotlin
-    implementation libs.rx.rxAndroid
-    implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.1'
-    // RXBinding
-    implementation libs.jakewharton.rxbinding
-    implementation libs.jakewharton.rxbindingAppcompat
-    implementation libs.jakewharton.rxbindingMaterial
+    // FlowBinding
+    implementation libs.github.flowBinding
+    implementation libs.github.flowBindingAppcompat
+    implementation libs.github.flowBindingMaterial
 
     implementation libs.airbnb.epoxy
     implementation libs.airbnb.epoxyGlide
     kapt libs.airbnb.epoxyProcessor
     implementation libs.airbnb.epoxyPaging
     implementation libs.airbnb.mavericks
-    //TODO: remove when entirely migrated to Flow
-    implementation libs.airbnb.mavericksRx
-
 
     // Work
     implementation libs.androidx.work
@@ -430,7 +425,7 @@ dependencies {
     implementation 'com.github.Armen101:AudioRecordView:1.0.5'
 
     // Custom Tab
-    implementation 'androidx.browser:browser:1.3.0'
+    implementation 'androidx.browser:browser:1.4.0'
 
     // Passphrase strength helper
     implementation 'com.nulab-inc:zxcvbn:1.5.2'
@@ -467,8 +462,8 @@ dependencies {
     implementation 'nl.dionsegijn:konfetti:1.3.2'
     implementation 'com.github.jetradarmobile:android-snowfall:1.2.1'
     // DI
-    implementation libs.dagger.dagger
-    kapt libs.dagger.daggerCompiler
+    implementation libs.dagger.hilt
+    kapt libs.dagger.hiltCompiler
 
     // UnifiedPush
     implementation 'com.github.UnifiedPush:android-connector:1.2.2'
@@ -483,7 +478,7 @@ dependencies {
     gplayImplementation 'com.google.android.gms:play-services-oss-licenses:17.0.0'
 
     implementation "androidx.emoji:emoji-appcompat:1.1.0"
-    implementation ('com.github.BillCarsonFr:JsonViewer:0.7')
+    implementation('com.github.BillCarsonFr:JsonViewer:0.7')
 
     // WebRTC
     // org.webrtc:google-webrtc is for development purposes only
@@ -499,7 +494,7 @@ dependencies {
 
     // QR-code
     // Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170
-    implementation 'com.google.zxing:core:3.4.1'
+    implementation 'com.google.zxing:core:3.3.3'
     implementation 'me.dm7.barcodescanner:zxing:1.9.13'
 
     // Emoji Keyboard
@@ -524,6 +519,9 @@ dependencies {
     // Plant Timber tree for test
     testImplementation libs.tests.timberJunitRule
     testImplementation libs.airbnb.mavericksTesting
+    testImplementation(libs.jetbrains.coroutinesTest) {
+        exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug"
+    }
 
     // Activate when you want to check for leaks, from time to time.
     //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
@@ -537,6 +535,9 @@ dependencies {
     androidTestImplementation libs.androidx.espressoIntents
     androidTestImplementation libs.tests.kluent
     androidTestImplementation libs.androidx.coreTesting
+    androidTestImplementation(libs.jetbrains.coroutinesTest) {
+        exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug"
+    }
     // Plant Timber tree for test
     androidTestImplementation libs.tests.timberJunitRule
     // "The one who serves a great Espresso"
diff --git a/vector/lint.xml b/vector/lint.xml
index dde29af62e..e534bdc355 100644
--- a/vector/lint.xml
+++ b/vector/lint.xml
@@ -68,6 +68,7 @@
     <!-- Timber -->
     <!--    This rule is failing on CI because it's marked as unknwown rule id :/-->
     <!--    <issue id="BinaryOperationInTimber" severity="error" />-->
+    <issue id="LogNotTimber" severity="error" />
 
     <!-- Wording -->
     <issue id="Typos" severity="error" />
diff --git a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt b/vector/src/androidTest/java/im/vector/app/EspressoExt.kt
index 823ce83015..fbcb9b8cb3 100644
--- a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt
+++ b/vector/src/androidTest/java/im/vector/app/EspressoExt.kt
@@ -18,7 +18,10 @@ package im.vector.app
 
 import android.app.Activity
 import android.view.View
+import androidx.annotation.StringRes
+import androidx.fragment.app.FragmentActivity
 import androidx.lifecycle.Observer
+import androidx.test.espresso.Espresso
 import androidx.test.espresso.IdlingRegistry
 import androidx.test.espresso.IdlingResource
 import androidx.test.espresso.PerformException
@@ -32,6 +35,12 @@ import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
 import androidx.test.runner.lifecycle.ActivityLifecycleCallback
 import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
 import androidx.test.runner.lifecycle.Stage
+import com.adevinta.android.barista.interaction.BaristaClickInteractions
+import com.google.android.material.bottomsheet.BottomSheetBehavior
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
+import im.vector.app.espresso.tools.waitUntilViewVisible
 import org.hamcrest.Matcher
 import org.hamcrest.Matchers
 import org.hamcrest.StringDescription
@@ -49,6 +58,18 @@ object EspressoHelper {
         }
         return currentActivity
     }
+
+    inline fun <reified T : VectorBaseBottomSheetDialogFragment<*>> getBottomSheetDialog(): BottomSheetDialogFragment? {
+        return (getCurrentActivity() as? FragmentActivity)
+                ?.supportFragmentManager
+                ?.fragments
+                ?.filterIsInstance<T>()
+                ?.firstOrNull()
+    }
+}
+
+fun getString(@StringRes id: Int): String {
+    return EspressoHelper.getCurrentActivity()!!.resources.getString(id)
 }
 
 fun waitForView(viewMatcher: Matcher<View>, timeout: Long = 10_000, waitForDisplayed: Boolean = true): ViewAction {
@@ -70,6 +91,8 @@ fun waitForView(viewMatcher: Matcher<View>, timeout: Long = 10_000, waitForDispl
             val endTime = startTime + timeout
             val visibleMatcher = isDisplayed()
 
+            uiController.loopMainThreadForAtLeast(100)
+
             do {
                 println("*** waitForView loop $view end:$endTime current:${System.currentTimeMillis()}")
                 val viewVisible = TreeIterables.breadthFirstViewTraversal(view)
@@ -205,3 +228,52 @@ fun allSecretsKnownIdling(session: Session): IdlingResource {
 
     return res
 }
+
+fun clickOnAndGoBack(@StringRes name: Int, block: () -> Unit) {
+    BaristaClickInteractions.clickOn(name)
+    block()
+    Espresso.pressBack()
+}
+
+inline fun <reified T : VectorBaseBottomSheetDialogFragment<*>> interactWithSheet(contentMatcher: Matcher<View>, noinline block: () -> Unit = {}) {
+    waitUntilViewVisible(contentMatcher)
+    val behaviour = (EspressoHelper.getBottomSheetDialog<T>()!!.dialog as BottomSheetDialog).behavior
+    withIdlingResource(BottomSheetResource(behaviour, BottomSheetBehavior.STATE_EXPANDED), block)
+    withIdlingResource(BottomSheetResource(behaviour, BottomSheetBehavior.STATE_HIDDEN)) {}
+}
+
+class BottomSheetResource(
+        private val bottomSheetBehavior: BottomSheetBehavior<*>,
+        @BottomSheetBehavior.State private val wantedState: Int
+) : IdlingResource, BottomSheetBehavior.BottomSheetCallback() {
+
+    private var isIdle: Boolean = false
+    private var resourceCallback: IdlingResource.ResourceCallback? = null
+
+    override fun onSlide(bottomSheet: View, slideOffset: Float) {}
+
+    override fun onStateChanged(bottomSheet: View, newState: Int) {
+        val wasIdle = isIdle
+        isIdle = newState == BottomSheetBehavior.STATE_EXPANDED
+        if (!wasIdle && isIdle) {
+            bottomSheetBehavior.removeBottomSheetCallback(this)
+            resourceCallback?.onTransitionToIdle()
+        }
+    }
+
+    override fun getName() = "BottomSheet awaiting state: $wantedState"
+
+    override fun isIdleNow() = isIdle
+
+    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
+        resourceCallback = callback
+
+        val state = bottomSheetBehavior.state
+        isIdle = state == wantedState
+        if (isIdle) {
+            resourceCallback!!.onTransitionToIdle()
+        } else {
+            bottomSheetBehavior.addBottomSheetCallback(this)
+        }
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/VerificationTestBase.kt b/vector/src/androidTest/java/im/vector/app/VerificationTestBase.kt
index a562287263..47e1e43be3 100644
--- a/vector/src/androidTest/java/im/vector/app/VerificationTestBase.kt
+++ b/vector/src/androidTest/java/im/vector/app/VerificationTestBase.kt
@@ -18,7 +18,7 @@ package im.vector.app
 
 import android.net.Uri
 import androidx.lifecycle.Observer
-import im.vector.app.ui.UiTestBase
+import im.vector.app.ui.robot.OnboardingRobot
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.launch
@@ -39,7 +39,7 @@ abstract class VerificationTestBase {
     val password = "password"
     val homeServerUrl: String = "http://10.0.2.2:8080"
 
-    protected val uiTestBase = UiTestBase()
+    protected val uiTestBase = OnboardingRobot()
 
     fun createAccountAndSync(matrix: Matrix,
                              userName: String,
diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt b/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
new file mode 100644
index 0000000000..2e329ebb6b
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.espresso.tools
+
+import android.content.ContentResolver
+import android.content.ContentValues
+import android.graphics.Bitmap
+import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.MediaStore
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import timber.log.Timber
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.OutputStream
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+private val SCREENSHOT_FOLDER_LOCATION = "${Environment.DIRECTORY_PICTURES}/failure_screenshots"
+private val deviceLanguage = Locale.getDefault().language
+
+class ScreenshotFailureRule : TestWatcher() {
+    override fun failed(e: Throwable?, description: Description) {
+        val screenShotName = "$deviceLanguage-${description.methodName}-${SimpleDateFormat("EEE-MMMM-dd-HH:mm:ss").format(Date())}"
+        val bitmap = getInstrumentation().uiAutomation.takeScreenshot()
+        storeFailureScreenshot(bitmap, screenShotName)
+    }
+}
+
+/**
+ * Stores screenshots in sdcard/Pictures/failure_screenshots
+ */
+private fun storeFailureScreenshot(bitmap: Bitmap, screenshotName: String) {
+    val contentResolver = getInstrumentation().targetContext.applicationContext.contentResolver
+
+    val contentValues = ContentValues().apply {
+        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
+        put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
+    }
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+        useMediaStoreScreenshotStorage(
+                contentValues,
+                contentResolver,
+                screenshotName,
+                SCREENSHOT_FOLDER_LOCATION,
+                bitmap
+        )
+    } else {
+        usePublicExternalScreenshotStorage(
+                contentValues,
+                contentResolver,
+                screenshotName,
+                SCREENSHOT_FOLDER_LOCATION,
+                bitmap
+        )
+    }
+}
+
+private fun useMediaStoreScreenshotStorage(
+        contentValues: ContentValues,
+        contentResolver: ContentResolver,
+        screenshotName: String,
+        screenshotLocation: String,
+        bitmap: Bitmap
+) {
+    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "$screenshotName.jpeg")
+    contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, screenshotLocation)
+    val uri: Uri? = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+    if (uri != null) {
+        contentResolver.openOutputStream(uri)?.let { saveScreenshotToStream(bitmap, it) }
+        contentResolver.update(uri, contentValues, null, null)
+    }
+}
+
+@Suppress("DEPRECATION")
+private fun usePublicExternalScreenshotStorage(
+        contentValues: ContentValues,
+        contentResolver: ContentResolver,
+        screenshotName: String,
+        screenshotLocation: String,
+        bitmap: Bitmap
+) {
+    val directory = File(Environment.getExternalStoragePublicDirectory(screenshotLocation).toString())
+    if (!directory.exists()) {
+        directory.mkdirs()
+    }
+    val file = File(directory, "$screenshotName.jpeg")
+    saveScreenshotToStream(bitmap, FileOutputStream(file))
+    contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+}
+
+private fun saveScreenshotToStream(bitmap: Bitmap, outputStream: OutputStream) {
+    outputStream.use {
+        try {
+            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, it)
+        } catch (e: IOException) {
+            Timber.e("Screenshot was not stored at this time")
+        }
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt b/vector/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt
index 2cdca62c74..7744d4b720 100644
--- a/vector/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt
+++ b/vector/src/androidTest/java/im/vector/app/espresso/tools/WaitActivity.kt
@@ -17,9 +17,18 @@
 package im.vector.app.espresso.tools
 
 import android.app.Activity
+import android.view.View
+import androidx.test.espresso.Espresso
+import androidx.test.espresso.matcher.ViewMatchers
 import im.vector.app.activityIdlingResource
+import im.vector.app.waitForView
 import im.vector.app.withIdlingResource
+import org.hamcrest.Matcher
 
-inline fun <reified T : Activity> waitUntilActivityVisible(noinline block: (() -> Unit)) {
+inline fun <reified T : Activity> waitUntilActivityVisible(noinline block: (() -> Unit) = {}) {
     withIdlingResource(activityIdlingResource(T::class.java), block)
 }
+
+fun waitUntilViewVisible(viewMatcher: Matcher<View>) {
+    Espresso.onView(ViewMatchers.isRoot()).perform(waitForView(viewMatcher))
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
index a9cb5274ed..f998a9f23c 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt
@@ -16,53 +16,19 @@
 
 package im.vector.app.ui
 
-import android.view.View
-import androidx.recyclerview.widget.RecyclerView
-import androidx.test.espresso.Espresso.onView
-import androidx.test.espresso.Espresso.pressBack
-import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
-import androidx.test.espresso.action.ViewActions.longClick
-import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
-import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
-import androidx.test.espresso.matcher.ViewMatchers.isRoot
-import androidx.test.espresso.matcher.ViewMatchers.withId
-import androidx.test.espresso.matcher.ViewMatchers.withText
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
-import com.adevinta.android.barista.assertion.BaristaListAssertions.assertListItemCount
-import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
-import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickBack
-import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
-import com.adevinta.android.barista.interaction.BaristaClickInteractions.longClickOn
-import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
-import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
-import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawer
-import com.adevinta.android.barista.interaction.BaristaEditTextInteractions.writeTo
-import com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItem
-import com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItemChild
-import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.clickMenu
-import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.openMenu
-import im.vector.app.BuildConfig
-import im.vector.app.EspressoHelper
 import im.vector.app.R
-import im.vector.app.SleepViewAction
-import im.vector.app.activityIdlingResource
-import im.vector.app.espresso.tools.clickOnPreference
-import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.espresso.tools.ScreenshotFailureRule
 import im.vector.app.features.MainActivity
-import im.vector.app.features.createdirect.CreateDirectRoomActivity
-import im.vector.app.features.home.HomeActivity
-import im.vector.app.features.home.room.detail.RoomDetailActivity
-import im.vector.app.features.login.LoginActivity
-import im.vector.app.features.roomdirectory.RoomDirectoryActivity
-import im.vector.app.initialSyncIdlingResource
-import im.vector.app.waitForView
-import im.vector.app.withIdlingResource
+import im.vector.app.getString
+import im.vector.app.ui.robot.ElementRobot
+import im.vector.app.ui.robot.withDeveloperMode
 import org.junit.Rule
 import org.junit.Test
+import org.junit.rules.RuleChain
 import org.junit.runner.RunWith
-import java.lang.Thread.sleep
 import java.util.UUID
 
 /**
@@ -73,9 +39,11 @@ import java.util.UUID
 class UiAllScreensSanityTest {
 
     @get:Rule
-    val activityRule = ActivityScenarioRule(MainActivity::class.java)
+    val testRule = RuleChain
+            .outerRule(ActivityScenarioRule(MainActivity::class.java))
+            .around(ScreenshotFailureRule())
 
-    private val uiTestBase = UiTestBase()
+    private val elementRobot = ElementRobot()
 
     // Last passing:
     // 2020-11-09
@@ -85,439 +53,63 @@ class UiAllScreensSanityTest {
     fun allScreensTest() {
         // Create an account
         val userId = "UiTest_" + UUID.randomUUID().toString()
-        uiTestBase.createAccount(userId = userId)
+        elementRobot.signUp(userId)
 
-        withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {
-            assertDisplayed(R.id.roomListContainer)
-            closeSoftKeyboard()
+        elementRobot.settings {
+            general { crawl() }
+            notifications { crawl() }
+            preferences { crawl() }
+            voiceAndVideo()
+            ignoredUsers()
+            securityAndPrivacy { crawl() }
+            labs()
+            advancedSettings { crawl() }
+            helpAndAbout { crawl() }
         }
 
-        val activity = EspressoHelper.getCurrentActivity()!!
-        val uiSession = (activity as HomeActivity).activeSessionHolder.getActiveSession()
-
-        withIdlingResource(initialSyncIdlingResource(uiSession)) {
-            assertDisplayed(R.id.roomListContainer)
+        elementRobot.newDirectMessage {
+            verifyQrCodeButton()
+            verifyInviteFriendsButton()
         }
 
-        assertDisplayed(R.id.bottomNavigationView)
+        elementRobot.newRoom {
+            createNewRoom {
+                crawl()
+                createRoom {
+                    val message = "Hello world!"
+                    postMessage(message)
+                    crawl()
+                    crawlMessage(message)
+                    openSettings { crawl() }
+                }
+            }
+        }
 
-        // Settings
-        navigateToSettings()
+        elementRobot.withDeveloperMode {
+            settings {
+                advancedSettings { crawlDeveloperOptions() }
+            }
+            roomList {
+                openRoom(getString(R.string.room_displayname_empty_room)) {
+                    val message = "Test view source"
+                    postMessage(message)
+                    openMessageMenu(message) {
+                        viewSource()
+                    }
+                }
+            }
+        }
 
-        // Create DM
-        clickOn(R.id.bottom_action_people)
-        createDm()
+        elementRobot.roomList {
+            verifyCreatedRoom()
+        }
 
-        // Create Room
-        // First navigate to the other tab
-        clickOn(R.id.bottom_action_rooms)
-        createRoom()
-
-        assertDisplayed(R.id.bottomNavigationView)
-
-        // Long click on the room
-        onView(withId(R.id.roomListView))
-                .perform(
-                        actionOnItem<RecyclerView.ViewHolder>(
-                                hasDescendant(withText(R.string.room_displayname_empty_room)),
-                                longClick()
-                        )
-                )
-        pressBack()
-
-        uiTestBase.signout()
-
-        // We have sent a message in a e2e room, accept to loose it
-        clickOn(R.id.exitAnywayButton)
-        // Dark pattern
-        clickDialogNegativeButton()
+        elementRobot.signout(expectSignOutWarning = true)
 
         // Login again on the same account
-        waitUntilActivityVisible<LoginActivity> {
-            assertDisplayed(R.id.loginSplashLogo)
-        }
-
-        uiTestBase.login(userId)
-        ignoreVerification()
-
-        uiTestBase.signout()
-        clickDialogPositiveButton()
-
+        elementRobot.login(userId)
+        elementRobot.dismissVerificationIfPresent()
         // TODO Deactivate account instead of logout?
-    }
-
-    private fun ignoreVerification() {
-        sleep(6000)
-        val activity = EspressoHelper.getCurrentActivity()!!
-
-        val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)
-        activity.runOnUiThread {
-            popup.performClick()
-        }
-
-        assertDisplayed(R.id.bottomSheetFragmentContainer)
-
-        onView(isRoot()).perform(SleepViewAction.sleep(2000))
-
-        clickOn(R.string.skip)
-        assertDisplayed(R.string.are_you_sure)
-        clickOn(R.string.skip)
-    }
-
-    private fun createRoom() {
-        clickOn(R.id.createGroupRoomButton)
-        waitUntilActivityVisible<RoomDirectoryActivity> {
-            assertDisplayed(R.id.publicRoomsList)
-        }
-        clickOn(R.string.create_new_room)
-
-        // Room access bottom sheet
-        clickOn(R.string.room_settings_room_access_private_title)
-        pressBack()
-
-        // Create
-        assertListItemCount(R.id.createRoomForm, 12)
-        clickListItemChild(R.id.createRoomForm, 11, R.id.form_submit_button)
-
-        waitUntilActivityVisible<RoomDetailActivity> {
-            assertDisplayed(R.id.roomDetailContainer)
-        }
-
-        clickOn(R.id.attachmentButton)
-        clickBack()
-
-        // Send a message
-        writeTo(R.id.composerEditText, "Hello world!")
-        clickOn(R.id.sendButton)
-
-        navigateToRoomSettings()
-
-        // Long click on the message
-        longClickOnMessageTest()
-
-        // Menu
-        openMenu()
-        pressBack()
-        clickMenu(R.id.voice_call)
-        pressBack()
-        clickMenu(R.id.video_call)
-        pressBack()
-        clickMenu(R.id.search)
-        pressBack()
-
-        pressBack()
-    }
-
-    private fun longClickOnMessageTest() {
-        // Test quick reaction
-        longClickOnMessage()
-        // Add quick reaction
-        clickOn("\uD83D\uDC4D️") // 👍
-
-        sleep(1000)
-
-        // Open reactions
-        longClickOn("\uD83D\uDC4D️") // 👍
-        pressBack()
-
-        // Test add reaction
-        longClickOnMessage()
-        clickOn(R.string.message_add_reaction)
-        // Filter
-        // TODO clickMenu(R.id.search)
-        // Wait for emoji to load, it's async now
-        sleep(2_000)
-        clickListItem(R.id.emojiRecyclerView, 4)
-
-        // Test Edit mode
-        longClickOnMessage()
-        clickOn(R.string.edit)
-        // TODO Cancel action
-        writeTo(R.id.composerEditText, "Hello universe!")
-        // Wait a bit for the keyboard layout to update
-        sleep(30)
-        clickOn(R.id.sendButton)
-        // Wait for the UI to update
-        sleep(1000)
-        // Open edit history
-        longClickOnMessage("Hello universe! (edited)")
-        clickOn(R.string.message_view_edit_history)
-        pressBack()
-    }
-
-    private fun longClickOnMessage(text: String = "Hello world!") {
-        onView(withId(R.id.timelineRecyclerView))
-                .perform(
-                        actionOnItem<RecyclerView.ViewHolder>(
-                                hasDescendant(withText(text)),
-                                longClick()
-                        )
-                )
-    }
-
-    private fun navigateToRoomSettings() {
-        clickOn(R.id.roomToolbarTitleView)
-        assertDisplayed(R.id.roomProfileAvatarView)
-
-        // Room settings
-        clickListItem(R.id.matrixProfileRecyclerView, 3)
-        navigateToRoomParameters()
-        pressBack()
-
-        // Notifications
-        clickListItem(R.id.matrixProfileRecyclerView, 5)
-        pressBack()
-
-        assertDisplayed(R.id.roomProfileAvatarView)
-
-        // People
-        clickListItem(R.id.matrixProfileRecyclerView, 7)
-        assertDisplayed(R.id.inviteUsersButton)
-        navigateToRoomPeople()
-        // Fab
-        navigateToInvite()
-        pressBack()
-        pressBack()
-
-        assertDisplayed(R.id.roomProfileAvatarView)
-
-        // Uploads
-        clickListItem(R.id.matrixProfileRecyclerView, 9)
-        // File tab
-        clickOn(R.string.uploads_files_title)
-        sleep(1000)
-        pressBack()
-
-        assertDisplayed(R.id.roomProfileAvatarView)
-
-        // Leave
-        clickListItem(R.id.matrixProfileRecyclerView, 13)
-        clickDialogNegativeButton()
-
-        // Advanced
-        // Room addresses
-        clickListItem(R.id.matrixProfileRecyclerView, 15)
-        onView(isRoot()).perform(waitForView(withText(R.string.room_alias_published_alias_title)))
-        pressBack()
-
-        // Room permissions
-        clickListItem(R.id.matrixProfileRecyclerView, 17)
-        onView(isRoot()).perform(waitForView(withText(R.string.room_permissions_title)))
-        clickOn(R.string.room_permissions_change_room_avatar)
-        clickDialogNegativeButton()
-        // Toggle
-        clickOn(R.string.show_advanced)
-        clickOn(R.string.hide_advanced)
-        pressBack()
-
-        // Menu share
-        // clickMenu(R.id.roomProfileShareAction)
-        // pressBack()
-
-        pressBack()
-    }
-
-    private fun navigateToRoomParameters() {
-        // Room history readability
-        clickListItem(R.id.roomSettingsRecyclerView, 4)
-        pressBack()
-
-        // Room access
-        clickListItem(R.id.roomSettingsRecyclerView, 6)
-        pressBack()
-    }
-
-    private fun navigateToInvite() {
-        assertDisplayed(R.id.inviteUsersButton)
-        clickOn(R.id.inviteUsersButton)
-        closeSoftKeyboard()
-        pressBack()
-    }
-
-    private fun navigateToRoomPeople() {
-        // Open first user
-        clickListItem(R.id.roomSettingsRecyclerView, 1)
-        sleep(1000)
-        assertDisplayed(R.id.memberProfilePowerLevelView)
-
-        // Verification
-        clickListItem(R.id.matrixProfileRecyclerView, 1)
-        clickBack()
-
-        // Role
-        clickListItem(R.id.matrixProfileRecyclerView, 3)
-        sleep(1000)
-        clickDialogNegativeButton()
-        sleep(1000)
-        clickBack()
-    }
-
-    private fun createDm() {
-        clickOn(R.id.createChatRoomButton)
-
-        withIdlingResource(activityIdlingResource(CreateDirectRoomActivity::class.java)) {
-            onView(withId(R.id.userListRecyclerView))
-                    .perform(waitForView(withText(R.string.qr_code)))
-            onView(withId(R.id.userListRecyclerView))
-                    .perform(waitForView(withText(R.string.invite_friends)))
-        }
-
-        closeSoftKeyboard()
-        pressBack()
-        pressBack()
-    }
-
-    private fun navigateToSettings() {
-        // clickOn(R.id.groupToolbarAvatarImageView)
-        openDrawer()
-        clickOn(R.id.homeDrawerHeaderSettingsView)
-
-        clickOn(R.string.settings_general_title)
-        navigateToSettingsGeneral()
-        pressBack()
-
-        clickOn(R.string.settings_notifications)
-        navigateToSettingsNotifications()
-        pressBack()
-
-        clickOn(R.string.settings_preferences)
-        navigateToSettingsPreferences()
-        pressBack()
-
-        clickOn(R.string.preference_voice_and_video)
-        pressBack()
-
-        clickOn(R.string.settings_ignored_users)
-        pressBack()
-
-        clickOn(R.string.settings_security_and_privacy)
-        navigateToSettingsSecurity()
-        pressBack()
-
-        clickOn(R.string.room_settings_labs_pref_title)
-        pressBack()
-
-        clickOn(R.string.settings_advanced_settings)
-        navigateToSettingsAdvanced()
-        pressBack()
-
-        clickOn(R.string.preference_root_help_about)
-        navigateToSettingsHelp()
-        pressBack()
-
-        pressBack()
-    }
-
-    private fun navigateToSettingsHelp() {
-        /*
-        clickOn(R.string.settings_app_info_link_title)
-        Cannot go back...
-        pressBack()
-        clickOn(R.string.settings_copyright)
-        pressBack()
-        clickOn(R.string.settings_app_term_conditions)
-        pressBack()
-        clickOn(R.string.settings_privacy_policy)
-        pressBack()
-         */
-        clickOn(R.string.settings_third_party_notices)
-        clickDialogPositiveButton()
-    }
-
-    private fun navigateToSettingsAdvanced() {
-        clickOnPreference(R.string.settings_notifications_targets)
-        pressBack()
-
-        clickOnPreference(R.string.settings_push_rules)
-        pressBack()
-
-        /* TODO P2 test developer screens
-        // Enable developer mode
-        clickOnSwitchPreference("SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY")
-
-        clickOnPreference(R.string.settings_account_data)
-        clickOn("m.push_rules")
-        pressBack()
-        pressBack()
-        clickOnPreference(R.string.settings_key_requests)
-        pressBack()
-
-        // Disable developer mode
-        clickOnSwitchPreference("SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY")
-         */
-    }
-
-    private fun navigateToSettingsSecurity() {
-        clickOnPreference(R.string.settings_active_sessions_show_all)
-        pressBack()
-
-        clickOnPreference(R.string.encryption_message_recovery)
-        // TODO go deeper here
-        pressBack()
-        /* Cannot exit
-        clickOnPreference(R.string.encryption_export_e2e_room_keys)
-        pressBack()
-         */
-    }
-
-    private fun navigateToSettingsPreferences() {
-        clickOn(R.string.settings_interface_language)
-        onView(isRoot())
-                .perform(waitForView(withText("Dansk (Danmark)")))
-        pressBack()
-        clickOn(R.string.settings_theme)
-        clickDialogNegativeButton()
-        clickOn(R.string.font_size)
-        clickDialogNegativeButton()
-    }
-
-    private fun navigateToSettingsNotifications() {
-        if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) {
-            clickOn(R.string.settings_notification_default)
-            pressBack()
-            clickOn(R.string.settings_notification_mentions_and_keywords)
-            // TODO Test adding a keyword?
-            pressBack()
-            clickOn(R.string.settings_notification_other)
-            pressBack()
-        } else {
-            clickOn(R.string.settings_notification_advanced)
-            pressBack()
-        }
-        /*
-        clickOn(R.string.settings_noisy_notifications_preferences)
-        TODO Cannot go back
-        pressBack()
-        clickOn(R.string.settings_silent_notifications_preferences)
-        pressBack()
-        clickOn(R.string.settings_call_notifications_preferences)
-        pressBack()
-         */
-        clickOnPreference(R.string.settings_notification_troubleshoot)
-        pressBack()
-    }
-
-    private fun navigateToSettingsGeneral() {
-        clickOn(R.string.settings_profile_picture)
-        clickDialogPositiveButton()
-        clickOn(R.string.settings_display_name)
-        clickDialogNegativeButton()
-        clickOn(R.string.settings_password)
-        clickDialogNegativeButton()
-        clickOn(R.string.settings_emails_and_phone_numbers_title)
-        pressBack()
-        clickOn(R.string.settings_discovery_manage)
-        clickOn(R.string.add_identity_server)
-        pressBack()
-        pressBack()
-        // Homeserver
-        clickOnPreference(R.string.settings_home_server)
-        pressBack()
-        // Identity server
-        clickOnPreference(R.string.settings_identity_server)
-        pressBack()
-        // Deactivate account
-        clickOnPreference(R.string.settings_deactivate_my_account)
-        pressBack()
+        elementRobot.signout(expectSignOutWarning = false)
     }
 }
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt
new file mode 100644
index 0000000000..505dfb33e9
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/CreateNewRoomRobot.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import com.adevinta.android.barista.assertion.BaristaListAssertions
+import com.adevinta.android.barista.interaction.BaristaClickInteractions
+import com.adevinta.android.barista.interaction.BaristaListInteractions
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.espresso.tools.waitUntilViewVisible
+import im.vector.app.features.home.room.detail.RoomDetailActivity
+
+class CreateNewRoomRobot(
+        var createdRoom: Boolean = false
+) {
+
+    fun createRoom(block: RoomDetailRobot.() -> Unit) {
+        createdRoom = true
+        BaristaListAssertions.assertListItemCount(R.id.createRoomForm, 12)
+        BaristaListInteractions.clickListItemChild(R.id.createRoomForm, 11, R.id.form_submit_button)
+        waitUntilActivityVisible<RoomDetailActivity> {
+            waitUntilViewVisible(withId(R.id.composerEditText))
+        }
+        block(RoomDetailRobot())
+        pressBack()
+    }
+
+    fun crawl() {
+        // Room access bottom sheet
+        BaristaClickInteractions.clickOn(R.string.room_settings_room_access_private_title)
+        pressBack()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt
new file mode 100644
index 0000000000..14c2d6284e
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/DialogRobot.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
+
+class DialogRobot(
+        var returnedToPreviousScreen: Boolean = false
+) {
+
+    fun negativeAction() {
+        clickDialogNegativeButton()
+        returnedToPreviousScreen = true
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
new file mode 100644
index 0000000000..a3bc5b26fc
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/ElementRobot.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import android.view.View
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
+import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawer
+import im.vector.app.EspressoHelper
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.espresso.tools.waitUntilViewVisible
+import im.vector.app.features.createdirect.CreateDirectRoomActivity
+import im.vector.app.features.home.HomeActivity
+import im.vector.app.features.login.LoginActivity
+import im.vector.app.initialSyncIdlingResource
+import im.vector.app.ui.robot.settings.SettingsRobot
+import im.vector.app.withIdlingResource
+import timber.log.Timber
+
+class ElementRobot {
+
+    fun signUp(userId: String) {
+        val onboardingRobot = OnboardingRobot()
+        onboardingRobot.createAccount(userId = userId)
+        waitForHome()
+    }
+
+    fun login(userId: String) {
+        val onboardingRobot = OnboardingRobot()
+        onboardingRobot.login(userId = userId)
+        waitForHome()
+    }
+
+    private fun waitForHome() {
+        waitUntilActivityVisible<HomeActivity> {
+            waitUntilViewVisible(withId(R.id.roomListContainer))
+        }
+        val activity = EspressoHelper.getCurrentActivity()!!
+        val uiSession = (activity as HomeActivity).activeSessionHolder.getActiveSession()
+        withIdlingResource(initialSyncIdlingResource(uiSession)) {
+            waitUntilViewVisible(withId(R.id.bottomNavigationView))
+        }
+    }
+
+    fun settings(block: SettingsRobot.() -> Unit) {
+        openDrawer()
+        clickOn(R.id.homeDrawerHeaderSettingsView)
+        block(SettingsRobot())
+        pressBack()
+        waitUntilViewVisible(withId(R.id.bottomNavigationView))
+    }
+
+    fun newDirectMessage(block: NewDirectMessageRobot.() -> Unit) {
+        clickOn(R.id.bottom_action_people)
+        clickOn(R.id.createChatRoomButton)
+        waitUntilActivityVisible<CreateDirectRoomActivity> {
+            waitUntilViewVisible(withId(R.id.userListSearch))
+        }
+        // close keyboard
+        pressBack()
+        block(NewDirectMessageRobot())
+        pressBack()
+        waitUntilViewVisible(withId(R.id.bottomNavigationView))
+    }
+
+    fun newRoom(block: NewRoomRobot.() -> Unit) {
+        clickOn(R.id.bottom_action_rooms)
+        RoomListRobot().newRoom { block() }
+        waitUntilViewVisible(withId(R.id.bottomNavigationView))
+    }
+
+    fun roomList(block: RoomListRobot.() -> Unit) {
+        clickOn(R.id.bottom_action_rooms)
+        block(RoomListRobot())
+        waitUntilViewVisible(withId(R.id.bottomNavigationView))
+    }
+
+    fun signout(expectSignOutWarning: Boolean) {
+        clickOn(R.id.groupToolbarAvatarImageView)
+        clickOn(R.id.homeDrawerHeaderSignoutView)
+
+        val isShowingSignOutWarning = kotlin.runCatching {
+            waitUntilViewVisible(withId(R.id.exitAnywayButton))
+        }.isSuccess
+
+        if (expectSignOutWarning != isShowingSignOutWarning) {
+            Timber.w("Unexpected sign out flow, expected warning to be: ${expectSignOutWarning.toWarningType()} but was ${isShowingSignOutWarning.toWarningType()}")
+        }
+
+        if (isShowingSignOutWarning) {
+            // We have sent a message in a e2e room, accept to loose it
+            clickOn(R.id.exitAnywayButton)
+            // Dark pattern
+            waitUntilViewVisible(withId(android.R.id.button2))
+            clickDialogNegativeButton()
+        } else {
+            waitUntilViewVisible(withId(android.R.id.button1))
+            clickDialogPositiveButton()
+        }
+
+        waitUntilActivityVisible<LoginActivity> {
+            assertDisplayed(R.id.loginSplashLogo)
+        }
+    }
+
+    fun dismissVerificationIfPresent() {
+        kotlin.runCatching {
+            Thread.sleep(6000)
+            val activity = EspressoHelper.getCurrentActivity()!!
+            val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)!!
+            activity.runOnUiThread { popup.performClick() }
+
+            waitUntilViewVisible(withId(R.id.bottomSheetFragmentContainer))
+            waitUntilViewVisible(ViewMatchers.withText(R.string.skip))
+            clickOn(R.string.skip)
+            assertDisplayed(R.string.are_you_sure)
+            clickOn(R.string.skip)
+            waitUntilViewVisible(withId(R.id.bottomSheetFragmentContainer))
+        }.onFailure { Timber.w("Verification popup missing", it) }
+    }
+}
+
+private fun Boolean.toWarningType() = if (this) "shown" else "skipped"
+
+fun ElementRobot.withDeveloperMode(block: ElementRobot.() -> Unit) {
+    settings { toggleDeveloperMode() }
+    block()
+    settings { toggleDeveloperMode() }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
new file mode 100644
index 0000000000..fd579c0d9f
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/MessageMenuRobot.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.test.espresso.Espresso.pressBack
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItem
+import im.vector.app.R
+import java.lang.Thread.sleep
+
+class MessageMenuRobot(
+        var autoClosed: Boolean = false
+) {
+
+    fun viewSource() {
+        clickOn(R.string.view_source)
+        // wait for library
+        sleep(1000)
+        pressBack()
+        autoClosed = true
+    }
+
+    fun editHistory() {
+        clickOn(R.string.message_view_edit_history)
+        pressBack()
+        autoClosed = true
+    }
+
+    fun addQuickReaction(quickReaction: String) {
+        clickOn(quickReaction)
+        autoClosed = true
+    }
+
+    fun addReactionFromEmojiPicker() {
+        clickOn(R.string.message_add_reaction)
+        // Wait for emoji to load, it's async now
+        sleep(2000)
+        clickListItem(R.id.emojiRecyclerView, 4)
+        autoClosed = true
+    }
+
+    fun edit() {
+        clickOn(R.string.edit)
+        autoClosed = true
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt
new file mode 100644
index 0000000000..34c43c73f7
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/NewDirectMessageRobot.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.test.espresso.Espresso
+import androidx.test.espresso.matcher.ViewMatchers
+import im.vector.app.R
+import im.vector.app.waitForView
+
+class NewDirectMessageRobot {
+
+    fun verifyQrCodeButton() {
+        Espresso.onView(ViewMatchers.withId(R.id.userListRecyclerView))
+                .perform(waitForView(ViewMatchers.withText(R.string.qr_code)))
+    }
+
+    fun verifyInviteFriendsButton() {
+        Espresso.onView(ViewMatchers.withId(R.id.userListRecyclerView))
+                .perform(waitForView(ViewMatchers.withText(R.string.invite_friends)))
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
new file mode 100644
index 0000000000..09ff1162c0
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/NewRoomRobot.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilViewVisible
+
+class NewRoomRobot(
+        var createdRoom: Boolean = false
+) {
+
+    fun createNewRoom(block: CreateNewRoomRobot.() -> Unit) {
+        clickOn(R.string.create_new_room)
+        waitUntilViewVisible(withId(R.id.createRoomForm))
+        val createNewRoomRobot = CreateNewRoomRobot()
+        block(createNewRoomRobot)
+        createdRoom = createNewRoomRobot.createdRoom
+        if (!createNewRoomRobot.createdRoom) {
+            pressBack()
+        }
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiTestBase.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
similarity index 88%
rename from vector/src/androidTest/java/im/vector/app/ui/UiTestBase.kt
rename to vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
index 2cef326501..fef5d4a1a2 100644
--- a/vector/src/androidTest/java/im/vector/app/ui/UiTestBase.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/OnboardingRobot.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package im.vector.app.ui
+package im.vector.app.ui.robot
 
 import androidx.test.espresso.Espresso.closeSoftKeyboard
 import androidx.test.espresso.Espresso.onView
@@ -26,11 +26,10 @@ import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assert
 import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
 import com.adevinta.android.barista.interaction.BaristaEditTextInteractions.writeTo
 import im.vector.app.R
-import im.vector.app.espresso.tools.waitUntilActivityVisible
-import im.vector.app.features.home.HomeActivity
 import im.vector.app.waitForView
 
-class UiTestBase {
+class OnboardingRobot {
+
     fun createAccount(userId: String, password: String = "password", homeServerUrl: String = "http://10.0.2.2:8080") {
         initSession(true, userId, password, homeServerUrl)
     }
@@ -76,15 +75,5 @@ class UiTestBase {
 
         closeSoftKeyboard()
         clickOn(R.id.loginSubmit)
-
-        // Wait
-        waitUntilActivityVisible<HomeActivity> {
-            assertDisplayed(R.id.homeDetailFragmentContainer)
-        }
-    }
-
-    fun signout() {
-        clickOn(R.id.groupToolbarAvatarImageView)
-        clickOn(R.id.homeDrawerHeaderSignoutView)
     }
 }
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
new file mode 100644
index 0000000000..24fe5adf64
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomDetailRobot.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.recyclerview.widget.RecyclerView
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.contrib.RecyclerViewActions
+import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import com.adevinta.android.barista.interaction.BaristaClickInteractions
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.longClickOn
+import com.adevinta.android.barista.interaction.BaristaEditTextInteractions.writeTo
+import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.clickMenu
+import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.openMenu
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilViewVisible
+import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet
+import im.vector.app.features.reactions.data.EmojiDataSource
+import im.vector.app.interactWithSheet
+import im.vector.app.waitForView
+import java.lang.Thread.sleep
+
+class RoomDetailRobot {
+
+    fun postMessage(content: String) {
+        writeTo(R.id.composerEditText, content)
+        waitUntilViewVisible(withId(R.id.sendButton))
+        clickOn(R.id.sendButton)
+        waitUntilViewVisible(withText(content))
+    }
+
+    fun crawl() {
+        clickOn(R.id.attachmentButton)
+        BaristaClickInteractions.clickBack()
+
+        // Menu
+        openMenu()
+        pressBack()
+        clickMenu(R.id.voice_call)
+        pressBack()
+        clickMenu(R.id.video_call)
+        pressBack()
+        clickMenu(R.id.search)
+        pressBack()
+    }
+
+    fun crawlMessage(message: String) {
+        // Test quick reaction
+        val quickReaction = EmojiDataSource.quickEmojis[0] // 👍
+        openMessageMenu(message) {
+            addQuickReaction(quickReaction)
+        }
+        // Open reactions
+        longClickOn(quickReaction)
+        // wait for bottom sheet
+        pressBack()
+        // Test add reaction
+        openMessageMenu(message) {
+            addReactionFromEmojiPicker()
+        }
+        // Test Edit mode
+        openMessageMenu(message) {
+            edit()
+        }
+        // TODO Cancel action
+        writeTo(R.id.composerEditText, "Hello universe!")
+        // Wait a bit for the keyboard layout to update
+        waitUntilViewVisible(withId(R.id.sendButton))
+        clickOn(R.id.sendButton)
+        // Wait for the UI to update
+        waitUntilViewVisible(withText("Hello universe! (edited)"))
+        // Open edit history
+        openMessageMenu("Hello universe! (edited)") {
+            editHistory()
+        }
+    }
+
+    fun openMessageMenu(message: String, block: MessageMenuRobot.() -> Unit) {
+        onView(withId(R.id.timelineRecyclerView))
+                .perform(
+                        RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
+                                ViewMatchers.hasDescendant(ViewMatchers.withText(message)),
+                                ViewActions.longClick()
+                        )
+                )
+        interactWithSheet<MessageActionsBottomSheet>(contentMatcher = withId(R.id.bottomSheetRecyclerView)) {
+            val messageMenuRobot = MessageMenuRobot()
+            block(messageMenuRobot)
+            if (!messageMenuRobot.autoClosed) {
+                pressBack()
+            }
+        }
+    }
+
+    fun openSettings(block: RoomSettingsRobot.() -> Unit) {
+        clickOn(R.id.roomToolbarTitleView)
+        waitForView(withId(R.id.roomProfileAvatarView))
+        sleep(1000)
+        block(RoomSettingsRobot())
+        pressBack()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
new file mode 100644
index 0000000000..dc07f06202
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomListRobot.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.recyclerview.widget.RecyclerView
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.contrib.RecyclerViewActions
+import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.features.roomdirectory.RoomDirectoryActivity
+
+class RoomListRobot {
+
+    fun openRoom(roomName: String, block: RoomDetailRobot.() -> Unit) {
+        clickOn(roomName)
+        block(RoomDetailRobot())
+        pressBack()
+    }
+
+    fun verifyCreatedRoom() {
+        onView(ViewMatchers.withId(R.id.roomListView))
+                .perform(
+                        RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
+                                ViewMatchers.hasDescendant(withText(R.string.room_displayname_empty_room)),
+                                ViewActions.longClick()
+                        )
+                )
+        pressBack()
+    }
+
+    fun newRoom(block: NewRoomRobot.() -> Unit) {
+        clickOn(R.id.createGroupRoomButton)
+        waitUntilActivityVisible<RoomDirectoryActivity> {
+            BaristaVisibilityAssertions.assertDisplayed(R.id.publicRoomsList)
+        }
+        val newRoomRobot = NewRoomRobot()
+        block(newRoomRobot)
+        if (!newRoomRobot.createdRoom) {
+            pressBack()
+        }
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt
new file mode 100644
index 0000000000..15186fe0c8
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/RoomSettingsRobot.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot
+
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
+import com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItem
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilActivityVisible
+import im.vector.app.espresso.tools.waitUntilViewVisible
+import im.vector.app.features.roommemberprofile.RoomMemberProfileActivity
+
+class RoomSettingsRobot {
+
+    fun crawl() {
+        // Room settings
+        clickListItem(R.id.matrixProfileRecyclerView, 3)
+        navigateToRoomParameters()
+        pressBack()
+
+        // Notifications
+        clickListItem(R.id.matrixProfileRecyclerView, 5)
+        pressBack()
+
+        assertDisplayed(R.id.roomProfileAvatarView)
+
+        // People
+        clickListItem(R.id.matrixProfileRecyclerView, 7)
+        assertDisplayed(R.id.inviteUsersButton)
+        navigateToRoomPeople()
+        // Fab
+        navigateToInvite()
+        pressBack()
+        pressBack()
+
+        assertDisplayed(R.id.roomProfileAvatarView)
+
+        // Uploads
+        clickListItem(R.id.matrixProfileRecyclerView, 9)
+        // File tab
+        clickOn(R.string.uploads_files_title)
+        waitUntilViewVisible(withText(R.string.uploads_media_title))
+        pressBack()
+        waitUntilViewVisible(withId(R.id.matrixProfileRecyclerView))
+
+        assertDisplayed(R.id.roomProfileAvatarView)
+
+        // Leave
+        leaveRoom {
+            negativeAction()
+        }
+
+        // Advanced
+        // Room addresses
+
+        clickListItem(R.id.matrixProfileRecyclerView, 15)
+        waitUntilViewVisible(withText(R.string.room_alias_published_alias_title))
+        pressBack()
+
+        // Room permissions
+        clickListItem(R.id.matrixProfileRecyclerView, 17)
+        waitUntilViewVisible(withText(R.string.room_permissions_title))
+        clickOn(R.string.room_permissions_change_room_avatar)
+        waitUntilViewVisible(withId(android.R.id.button2))
+        clickDialogNegativeButton()
+        waitUntilViewVisible(withText(R.string.room_permissions_title))
+        // Toggle
+        clickOn(R.string.show_advanced)
+        clickOn(R.string.hide_advanced)
+        pressBack()
+
+        // Menu share
+        // clickMenu(R.id.roomProfileShareAction)
+        // pressBack()
+    }
+
+    private fun leaveRoom(block: DialogRobot.() -> Unit) {
+        clickListItem(R.id.matrixProfileRecyclerView, 13)
+        waitUntilViewVisible(withId(android.R.id.button2))
+        val dialogRobot = DialogRobot()
+        block(dialogRobot)
+        if (dialogRobot.returnedToPreviousScreen) {
+            waitUntilViewVisible(withId(R.id.matrixProfileRecyclerView))
+        }
+    }
+
+    private fun navigateToRoomParameters() {
+        // Room history readability
+        clickListItem(R.id.roomSettingsRecyclerView, 4)
+        pressBack()
+
+        // Room access
+        clickListItem(R.id.roomSettingsRecyclerView, 6)
+        pressBack()
+    }
+
+    private fun navigateToInvite() {
+        assertDisplayed(R.id.inviteUsersButton)
+        clickOn(R.id.inviteUsersButton)
+        ViewActions.closeSoftKeyboard()
+        pressBack()
+    }
+
+    private fun navigateToRoomPeople() {
+        // Open first user
+        clickListItem(R.id.roomSettingsRecyclerView, 1)
+        waitUntilActivityVisible<RoomMemberProfileActivity> {
+            waitUntilViewVisible(withId(R.id.memberProfilePowerLevelView))
+        }
+
+        // Verification
+        clickListItem(R.id.matrixProfileRecyclerView, 1)
+        waitUntilViewVisible(withId(R.id.bottomSheetRecyclerView))
+        pressBack()
+        waitUntilViewVisible(withId(R.id.matrixProfileRecyclerView))
+
+        // Role
+        clickListItem(R.id.matrixProfileRecyclerView, 3)
+        waitUntilViewVisible(withId(android.R.id.button2))
+        clickDialogNegativeButton()
+        waitUntilViewVisible(withId(R.id.matrixProfileRecyclerView))
+        pressBack()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt
new file mode 100644
index 0000000000..4aeb8903dd
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsAdvancedRobot.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot.settings
+
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import im.vector.app.R
+import im.vector.app.espresso.tools.clickOnPreference
+import im.vector.app.espresso.tools.waitUntilViewVisible
+
+class SettingsAdvancedRobot {
+
+    fun crawl() {
+        clickOnPreference(R.string.settings_notifications_targets)
+        pressBack()
+
+        clickOnPreference(R.string.settings_push_rules)
+        pressBack()
+    }
+
+    fun toggleDeveloperMode() {
+        clickOn(R.string.settings_developer_mode_summary)
+    }
+
+    fun crawlDeveloperOptions() {
+        clickOnPreference(R.string.settings_account_data)
+        waitUntilViewVisible(withText("m.push_rules"))
+        clickOn("m.push_rules")
+        pressBack()
+        pressBack()
+        clickOnPreference(R.string.settings_key_requests)
+        pressBack()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt
new file mode 100644
index 0000000000..9082eaa889
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsGeneralRobot.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot.settings
+
+import androidx.test.espresso.Espresso.pressBack
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
+import im.vector.app.R
+import im.vector.app.espresso.tools.clickOnPreference
+
+class SettingsGeneralRobot {
+
+    fun crawl() {
+        clickOn(R.string.settings_profile_picture)
+        clickDialogPositiveButton()
+        clickOn(R.string.settings_display_name)
+        clickDialogNegativeButton()
+        clickOn(R.string.settings_password)
+        clickDialogNegativeButton()
+        clickOn(R.string.settings_emails_and_phone_numbers_title)
+        pressBack()
+        clickOn(R.string.settings_discovery_manage)
+        clickOn(R.string.add_identity_server)
+        pressBack()
+        pressBack()
+        // Homeserver
+        clickOnPreference(R.string.settings_home_server)
+        pressBack()
+        // Identity server
+        clickOnPreference(R.string.settings_identity_server)
+        pressBack()
+        // Deactivate account
+        clickOnPreference(R.string.settings_deactivate_my_account)
+        pressBack()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
new file mode 100644
index 0000000000..75f610d016
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsHelpRobot.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot.settings
+
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
+import im.vector.app.R
+
+class SettingsHelpRobot {
+
+    fun crawl() {
+        /*
+        clickOn(R.string.settings_app_info_link_title)
+        Cannot go back...
+        pressBack()
+        clickOn(R.string.settings_copyright)
+        pressBack()
+        clickOn(R.string.settings_app_term_conditions)
+        pressBack()
+        clickOn(R.string.settings_privacy_policy)
+        pressBack()
+         */
+        clickOn(R.string.settings_third_party_notices)
+        clickDialogPositiveButton()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt
new file mode 100644
index 0000000000..448552ba8e
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot.settings
+
+import androidx.test.espresso.Espresso.pressBack
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import im.vector.app.BuildConfig
+import im.vector.app.R
+import im.vector.app.espresso.tools.clickOnPreference
+
+class SettingsNotificationsRobot {
+
+    fun crawl() {
+        if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) {
+            clickOn(R.string.settings_notification_default)
+            pressBack()
+            clickOn(R.string.settings_notification_mentions_and_keywords)
+            // TODO Test adding a keyword?
+            pressBack()
+            clickOn(R.string.settings_notification_other)
+            pressBack()
+        } else {
+            clickOn(R.string.settings_notification_advanced)
+            pressBack()
+        }
+        /*
+        clickOn(R.string.settings_noisy_notifications_preferences)
+        TODO Cannot go back
+        pressBack()
+        clickOn(R.string.settings_silent_notifications_preferences)
+        pressBack()
+        clickOn(R.string.settings_call_notifications_preferences)
+        pressBack()
+         */
+        clickOnPreference(R.string.settings_notification_troubleshoot)
+        pressBack()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt
new file mode 100644
index 0000000000..438bbac5a5
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsPreferencesRobot.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot.settings
+
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
+import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
+import im.vector.app.R
+import im.vector.app.espresso.tools.waitUntilViewVisible
+
+class SettingsPreferencesRobot {
+
+    fun crawl() {
+        clickOn(R.string.settings_interface_language)
+        waitUntilViewVisible(withText("Dansk (Danmark)"))
+        pressBack()
+        clickOn(R.string.settings_theme)
+        clickDialogNegativeButton()
+        clickOn(R.string.font_size)
+        clickDialogNegativeButton()
+    }
+}
diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
new file mode 100644
index 0000000000..a9c053f6c3
--- /dev/null
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsRobot.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.ui.robot.settings
+
+import im.vector.app.R
+import im.vector.app.clickOnAndGoBack
+
+class SettingsRobot {
+
+    fun toggleDeveloperMode() {
+        advancedSettings {
+            toggleDeveloperMode()
+        }
+    }
+
+    fun general(block: SettingsGeneralRobot.() -> Unit) {
+        clickOnAndGoBack(R.string.settings_general_title) { block(SettingsGeneralRobot()) }
+    }
+
+    fun notifications(block: SettingsNotificationsRobot.() -> Unit) {
+        clickOnAndGoBack(R.string.settings_notifications) { block(SettingsNotificationsRobot()) }
+    }
+
+    fun preferences(block: SettingsPreferencesRobot.() -> Unit) {
+        clickOnAndGoBack(R.string.settings_preferences) { block(SettingsPreferencesRobot()) }
+    }
+
+    fun voiceAndVideo(block: () -> Unit = {}) {
+        clickOnAndGoBack(R.string.preference_voice_and_video) { block() }
+    }
+
+    fun ignoredUsers(block: () -> Unit = {}) {
+        clickOnAndGoBack(R.string.settings_ignored_users) { block() }
+    }
+
+    fun securityAndPrivacy(block: SettingsSecurityRobot.() -> Unit) {
+        clickOnAndGoBack(R.string.settings_security_and_privacy) { block(SettingsSecurityRobot()) }
+    }
+
+    fun labs(block: () -> Unit = {}) {
+        clickOnAndGoBack(R.string.room_settings_labs_pref_title) { block() }
+    }
+
+    fun advancedSettings(block: SettingsAdvancedRobot.() -> Unit) {
+        clickOnAndGoBack(R.string.settings_advanced_settings) {
+            block(SettingsAdvancedRobot())
+        }
+    }
+
+    fun helpAndAbout(block: SettingsHelpRobot.() -> Unit) {
+        clickOnAndGoBack(R.string.preference_root_help_about) { block(SettingsHelpRobot()) }
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/InstantRxRule.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
similarity index 51%
rename from vector/src/test/java/im/vector/app/test/InstantRxRule.kt
rename to vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
index 1145cb7dd1..f2607bbc1c 100644
--- a/vector/src/test/java/im/vector/app/test/InstantRxRule.kt
+++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsSecurityRobot.kt
@@ -14,19 +14,24 @@
  * limitations under the License.
  */
 
-package im.vector.app.test
+package im.vector.app.ui.robot.settings
 
-import io.reactivex.android.plugins.RxAndroidPlugins
-import io.reactivex.plugins.RxJavaPlugins
-import io.reactivex.schedulers.Schedulers
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
+import androidx.test.espresso.Espresso
+import im.vector.app.R
+import im.vector.app.espresso.tools.clickOnPreference
 
-class InstantRxRule : TestRule {
-    override fun apply(base: Statement, description: Description?): Statement {
-        RxJavaPlugins.setInitNewThreadSchedulerHandler { Schedulers.trampoline() }
-        RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
-        return base
+class SettingsSecurityRobot {
+
+    fun crawl() {
+        clickOnPreference(R.string.settings_active_sessions_show_all)
+        Espresso.pressBack()
+
+        clickOnPreference(R.string.encryption_message_recovery)
+        // TODO go deeper here
+        Espresso.pressBack()
+        /* Cannot exit
+        clickOnPreference(R.string.encryption_export_e2e_room_keys)
+        pressBack()
+         */
     }
 }
diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt
index 303a3a14ba..960994b169 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt
@@ -24,9 +24,9 @@ import android.os.Build
 import androidx.core.app.NotificationCompat
 import androidx.core.app.Person
 import androidx.core.content.getSystemService
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.registerStartForActivityResult
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
@@ -50,6 +50,7 @@ import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData
 import timber.log.Timber
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
 
     override fun getBinding() = ActivityDebugMenuBinding.inflate(layoutInflater)
@@ -57,10 +58,6 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
     @Inject
     lateinit var activeSessionHolder: ActiveSessionHolder
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     private lateinit var buffer: ByteArray
 
     override fun initUiAndData() {
diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt
index 048c64bc3a..a35bb40f8f 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt
@@ -22,6 +22,7 @@ import android.os.Build
 import android.widget.Toast
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.core.utils.checkPermissions
@@ -31,6 +32,7 @@ import im.vector.app.core.utils.registerForPermissionsResult
 import im.vector.app.databinding.ActivityDebugPermissionBinding
 import timber.log.Timber
 
+@AndroidEntryPoint
 class DebugPermissionActivity : VectorBaseActivity<ActivityDebugPermissionBinding>() {
 
     override fun getBinding() = ActivityDebugPermissionBinding.inflate(layoutInflater)
diff --git a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt
new file mode 100644
index 0000000000..39b5c4a976
--- /dev/null
+++ b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.di
+
+import android.content.Context
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import im.vector.app.core.services.GuardServiceStarter
+import im.vector.app.fdroid.service.FDroidGuardServiceStarter
+import im.vector.app.features.settings.VectorPreferences
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class FlavorModule {
+
+    companion object {
+
+        @Provides
+        @JvmStatic
+        fun provideGuardServiceStarter(preferences: VectorPreferences, appContext: Context): GuardServiceStarter {
+            return FDroidGuardServiceStarter(preferences, appContext)
+        }
+    }
+}
diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/service/FDroidGuardServiceStarter.kt b/vector/src/fdroid/java/im/vector/app/fdroid/service/FDroidGuardServiceStarter.kt
new file mode 100644
index 0000000000..d421c8bb87
--- /dev/null
+++ b/vector/src/fdroid/java/im/vector/app/fdroid/service/FDroidGuardServiceStarter.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.fdroid.service
+
+import android.content.Context
+import android.content.Intent
+import androidx.core.content.ContextCompat
+import im.vector.app.core.services.GuardServiceStarter
+import im.vector.app.features.settings.VectorPreferences
+import timber.log.Timber
+import javax.inject.Inject
+
+class FDroidGuardServiceStarter @Inject constructor(
+        private val preferences: VectorPreferences,
+        private val appContext: Context
+) : GuardServiceStarter {
+
+    override fun start() {
+        if (preferences.isBackgroundSyncEnabled()) {
+            try {
+                Timber.i("## Sync: starting GuardService")
+                val intent = Intent(appContext, GuardService::class.java)
+                ContextCompat.startForegroundService(appContext, intent)
+            } catch (ex: Throwable) {
+                Timber.e("## Sync: ERROR starting GuardService")
+            }
+        }
+    }
+
+    override fun stop() {
+        val intent = Intent(appContext, GuardService::class.java)
+        appContext.stopService(intent)
+    }
+}
diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/service/GuardService.kt b/vector/src/fdroid/java/im/vector/app/fdroid/service/GuardService.kt
new file mode 100644
index 0000000000..053cf87c17
--- /dev/null
+++ b/vector/src/fdroid/java/im/vector/app/fdroid/service/GuardService.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.app.fdroid.service
+
+import android.content.Intent
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.services.VectorService
+import im.vector.app.features.notifications.NotificationUtils
+import javax.inject.Inject
+
+/**
+ * This no-op foreground service acts as a deterrent to the system eagerly killing the app process.
+ *
+ * Keeping the app process alive avoids some OEMs ignoring scheduled WorkManager and AlarmManager tasks
+ * when the app is not in the foreground.
+ */
+@AndroidEntryPoint
+class GuardService : VectorService() {
+
+    @Inject lateinit var notificationUtils: NotificationUtils
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        val notificationSubtitleRes = R.string.notification_listening_for_notifications
+        val notification = notificationUtils.buildForegroundServiceNotification(notificationSubtitleRes, false)
+        startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification)
+        return START_STICKY
+    }
+}
diff --git a/vector/src/gplay/AndroidManifest.xml b/vector/src/gplay/AndroidManifest.xml
index 5109ab90da..2eaec5a867 100755
--- a/vector/src/gplay/AndroidManifest.xml
+++ b/vector/src/gplay/AndroidManifest.xml
@@ -11,4 +11,4 @@
         </receiver>
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt
new file mode 100644
index 0000000000..61fd476c87
--- /dev/null
+++ b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.di
+
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import im.vector.app.core.services.GuardServiceStarter
+
+@InstallIn(SingletonComponent::class)
+@Module
+abstract class FlavorModule {
+
+    companion object {
+
+        @Provides
+        @JvmStatic
+        fun provideGuardServiceStarter(): GuardServiceStarter {
+            return object : GuardServiceStarter {}
+        }
+    }
+}
diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt
new file mode 100644
index 0000000000..89270cce55
--- /dev/null
+++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.app.gplay.features.settings.troubleshoot
+
+import android.content.Intent
+import androidx.activity.result.ActivityResultLauncher
+import androidx.fragment.app.FragmentActivity
+import com.google.firebase.messaging.FirebaseMessaging
+import im.vector.app.R
+import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.utils.startAddGoogleAccountIntent
+import im.vector.app.features.settings.troubleshoot.TroubleshootTest
+import im.vector.app.push.fcm.FcmHelper
+import timber.log.Timber
+import javax.inject.Inject
+
+/*
+* Test that app can successfully retrieve a token via firebase
+ */
+class TestFirebaseToken @Inject constructor(private val context: FragmentActivity,
+                                            private val stringProvider: StringProvider) : TroubleshootTest(R.string.settings_troubleshoot_test_fcm_title) {
+
+    override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
+        status = TestStatus.RUNNING
+        try {
+            FirebaseMessaging.getInstance().token
+                    .addOnCompleteListener(context) { task ->
+                        if (!task.isSuccessful) {
+                            // Can't find where this constant is (not documented -or deprecated in docs- and all obfuscated)
+                            description = when (val errorMsg = task.exception?.localizedMessage ?: "Unknown") {
+                                "SERVICE_NOT_AVAILABLE"  -> {
+                                    stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_service_not_available, errorMsg)
+                                }
+                                "TOO_MANY_REGISTRATIONS" -> {
+                                    stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_too_many_registration, errorMsg)
+                                }
+                                "ACCOUNT_MISSING"        -> {
+                                    quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_fcm_failed_account_missing_quick_fix) {
+                                        override fun doFix() {
+                                            startAddGoogleAccountIntent(context, activityResultLauncher)
+                                        }
+                                    }
+                                    stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_account_missing, errorMsg)
+                                }
+                                else                     -> {
+                                    stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed, errorMsg)
+                                }
+                            }
+                            status = TestStatus.FAILED
+                        } else {
+                            task.result?.let { token ->
+                                val tok = token.take(8) + "********************"
+                                description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_success, tok)
+                                Timber.e("Retrieved FCM token success [$tok].")
+                                // Ensure it is well store in our local storage
+                                FcmHelper.storeFcmToken(context, token)
+                            }
+                            status = TestStatus.SUCCESS
+                        }
+                    }
+        } catch (e: Throwable) {
+            description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed, e.localizedMessage)
+            status = TestStatus.FAILED
+        }
+    }
+}
diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPlayServices.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPlayServices.kt
index 1f822d6060..cc682e7a5f 100644
--- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPlayServices.kt
+++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPlayServices.kt
@@ -17,7 +17,7 @@ package im.vector.app.gplay.features.settings.troubleshoot
 
 import android.content.Intent
 import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
 import com.google.android.gms.common.ConnectionResult
 import com.google.android.gms.common.GoogleApiAvailability
 import im.vector.app.R
@@ -29,7 +29,7 @@ import javax.inject.Inject
 /*
 * Check that the play services APK is available an up-to-date. If needed provide quick fix to install it.
  */
-class TestPlayServices @Inject constructor(private val context: AppCompatActivity,
+class TestPlayServices @Inject constructor(private val context: FragmentActivity,
                                            private val stringProvider: StringProvider) :
     TroubleshootTest(R.string.settings_troubleshoot_test_play_services_title) {
 
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index b8d5a1a351..713d656f8d 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -4,7 +4,10 @@
     package="im.vector.app">
 
     <!-- Needed for VOIP call to detect and switch to headset-->
-    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission
+        android:name="android.permission.BLUETOOTH"
+        android:maxSdkVersion="30" />
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@@ -351,6 +354,7 @@
         <activity android:name=".features.spaces.manage.SpaceManageActivity" />
         <activity android:name=".features.spaces.people.SpacePeopleActivity" />
         <activity android:name=".features.spaces.leave.SpaceLeaveAdvancedActivity" />
+        <activity android:name=".features.poll.create.CreatePollActivity" />
 
         <!-- Services -->
 
@@ -441,7 +445,9 @@
         </receiver>
 
         <!-- For the fallback with sync loop if the user don't have FCM or a UnifiedPush Distributor -->
-        <receiver android:name=".core.receiver.OnApplicationUpgradeOrRebootReceiver">
+        <receiver
+            android:name=".core.receiver.OnApplicationUpgradeOrRebootReceiver"
+            android:exported="false">
             <intent-filter>
                 <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -453,6 +459,21 @@
             android:enabled="true"
             android:exported="false" />
 
+        <!-- Temporary fix for Android 12. android:exported has to be explicitly set when targeting Android 12
+        Do it for services coming from dependencies - BEGIN -->
+        <service
+            android:name="org.jitsi.meet.sdk.ConnectionService"
+            android:exported="false"
+            tools:node="merge" />
+        <service
+            android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
+            android:exported="false"
+            tools:node="merge" />
+        <service
+            android:name="androidx.sharetarget.ChooserTargetServiceCompat"
+            android:exported="false"
+            tools:node="merge" />
+        <!-- Temporary fix for Android 12 change - END -->
     </application>
 
 </manifest>
diff --git a/vector/src/main/assets/open_source_licenses.html b/vector/src/main/assets/open_source_licenses.html
index 23b64a2f43..b4165da1e6 100755
--- a/vector/src/main/assets/open_source_licenses.html
+++ b/vector/src/main/assets/open_source_licenses.html
@@ -284,25 +284,9 @@ SOFTWARE.
         Copyright 2012 The Dagger Authors
     </li>
     <li>
-        <b>rxkotlin</b>
+        <b>FlowBinding</b>
         <br/>
-        Copyright io.reactivex.
-    </li>
-    <li>
-        <b>rxandroid</b>
-        <br/>
-        Copyright io.reactivex.
-    </li>
-    <li>
-        <b>rxrelay</b>
-        <br/>
-        Copyright 2014 Netflix, Inc.
-        Copyright 2015 Jake Wharton
-    </li>
-    <li>
-        <b>rxbinding</b>
-        <br/>
-        Copyright (C) 2015 Jake Wharton
+        Copyright 2019 Yang Chen
     </li>
     <li>
         <b>Epoxy</b>
diff --git a/vector/src/main/java/im/vector/app/AppStateHandler.kt b/vector/src/main/java/im/vector/app/AppStateHandler.kt
index 337ae35491..1ace5c73e9 100644
--- a/vector/src/main/java/im/vector/app/AppStateHandler.kt
+++ b/vector/src/main/java/im/vector/app/AppStateHandler.kt
@@ -16,16 +16,20 @@
 
 package im.vector.app
 
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import arrow.core.Option
 import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.utils.BehaviorDataSource
 import im.vector.app.features.session.coroutineScope
 import im.vector.app.features.ui.UiStateRepository
-import io.reactivex.disposables.CompositeDisposable
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.Session
@@ -52,12 +56,12 @@ class AppStateHandler @Inject constructor(
         private val sessionDataSource: ActiveSessionDataSource,
         private val uiStateRepository: UiStateRepository,
         private val activeSessionHolder: ActiveSessionHolder
-) : LifecycleObserver {
+) : DefaultLifecycleObserver {
 
-    private val compositeDisposable = CompositeDisposable()
+    private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
     private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomGroupingMethod>>(Option.empty())
 
-    val selectedRoomGroupingObservable = selectedSpaceDataSource.observe()
+    val selectedRoomGroupingObservable = selectedSpaceDataSource.stream()
 
     var onSwitchSpaceListener: OnSwitchSpaceListener? = null
 
@@ -108,9 +112,9 @@ class AppStateHandler @Inject constructor(
     }
 
     private fun observeActiveSession() {
-        sessionDataSource.observe()
+        sessionDataSource.stream()
                 .distinctUntilChanged()
-                .subscribe {
+                .onEach {
                     // sessionDataSource could already return a session while activeSession holder still returns null
                     it.orNull()?.let { session ->
                         if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) {
@@ -119,9 +123,8 @@ class AppStateHandler @Inject constructor(
                             setCurrentGroup(uiStateRepository.getSelectedGroup(session.sessionId), session)
                         }
                     }
-                }.also {
-                    compositeDisposable.add(it)
                 }
+                .launchIn(coroutineScope)
     }
 
     fun safeActiveSpaceId(): String? {
@@ -132,14 +135,12 @@ class AppStateHandler @Inject constructor(
         return (selectedSpaceDataSource.currentValue?.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
-    fun entersForeground() {
+    override fun onResume(owner: LifecycleOwner) {
         observeActiveSession()
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
-    fun entersBackground() {
-        compositeDisposable.clear()
+    override fun onPause(owner: LifecycleOwner) {
+        coroutineScope.coroutineContext.cancelChildren()
         val session = activeSessionHolder.getSafeActiveSession() ?: return
         when (val currentMethod = selectedSpaceDataSource.currentValue?.orNull() ?: RoomGroupingMethod.BySpace(null)) {
             is RoomGroupingMethod.BySpace       -> {
diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt
index a137d5b5be..db5bc8e59e 100644
--- a/vector/src/main/java/im/vector/app/VectorApplication.kt
+++ b/vector/src/main/java/im/vector/app/VectorApplication.kt
@@ -27,9 +27,8 @@ import android.os.HandlerThread
 import android.os.StrictMode
 import androidx.core.provider.FontRequest
 import androidx.core.provider.FontsContractCompat
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.ProcessLifecycleOwner
 import androidx.multidex.MultiDex
 import com.airbnb.epoxy.EpoxyAsyncUtil
@@ -39,14 +38,11 @@ import com.facebook.stetho.Stetho
 import com.gabrielittner.threetenbp.LazyThreeTen
 import com.vanniktech.emoji.EmojiManager
 import com.vanniktech.emoji.google.GoogleEmojiProvider
+import dagger.hilt.android.HiltAndroidApp
 import de.spiritcroc.matrixsdk.StaticScSdkHelper
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.DaggerVectorComponent
-import im.vector.app.core.di.HasVectorInjector
-import im.vector.app.core.di.VectorComponent
 import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.extensions.startSyncing
-import im.vector.app.core.rx.RxConfig
 import im.vector.app.features.call.webrtc.WebRtcCallManager
 import im.vector.app.features.configuration.VectorConfiguration
 import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog
@@ -56,6 +52,7 @@ import im.vector.app.features.notifications.NotificationDrawerManager
 import im.vector.app.features.notifications.NotificationUtils
 import im.vector.app.features.pin.PinLocker
 import im.vector.app.features.popup.PopupAlertManager
+import im.vector.app.features.rageshake.VectorFileLogger
 import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
 import im.vector.app.features.room.VectorRoomDisplayNameFallbackProvider
 import im.vector.app.features.settings.VectorLocale
@@ -76,9 +73,9 @@ import java.util.concurrent.Executors
 import javax.inject.Inject
 import androidx.work.Configuration as WorkConfiguration
 
+@HiltAndroidApp
 class VectorApplication :
         Application(),
-        HasVectorInjector,
         MatrixConfiguration.Provider,
         WorkConfiguration.Provider {
 
@@ -95,13 +92,11 @@ class VectorApplication :
     @Inject lateinit var versionProvider: VersionProvider
     @Inject lateinit var notificationUtils: NotificationUtils
     @Inject lateinit var appStateHandler: AppStateHandler
-    @Inject lateinit var rxConfig: RxConfig
     @Inject lateinit var popupAlertManager: PopupAlertManager
     @Inject lateinit var pinLocker: PinLocker
     @Inject lateinit var callManager: WebRtcCallManager
     @Inject lateinit var invitesAcceptor: InvitesAcceptor
-
-    lateinit var vectorComponent: VectorComponent
+    @Inject lateinit var vectorFileLogger: VectorFileLogger
 
     // font thread handler
     private var fontThreadHandler: Handler? = null
@@ -119,11 +114,8 @@ class VectorApplication :
         enableStrictModeIfNeeded()
         super.onCreate()
         appContext = this
-        vectorComponent = DaggerVectorComponent.factory().create(this)
-        vectorComponent.inject(this)
         invitesAcceptor.initialize()
         vectorUncaughtExceptionHandler.activate(this)
-        rxConfig.setupRxPlugin()
 
         // SC SDK helper initialization
         StaticScSdkHelper.scSdkPreferenceProvider = vectorPreferences
@@ -136,7 +128,7 @@ class VectorApplication :
         if (BuildConfig.DEBUG) {
             Timber.plant(Timber.DebugTree())
         }
-        Timber.plant(vectorComponent.vectorFileLogger())
+        Timber.plant(vectorFileLogger)
 
         if (BuildConfig.DEBUG) {
             Stetho.initializeWithDefaults(this)
@@ -177,9 +169,8 @@ class VectorApplication :
 
         ProcessLifecycleOwner.get().lifecycle.addObserver(startSyncOnFirstStart)
 
-        ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleObserver {
-            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
-            fun entersForeground() {
+        ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
+            override fun onResume(owner: LifecycleOwner) {
                 Timber.i("App entered foreground")
                 StateHelper.onEnterForeground(appContext, activeSessionHolder)
                 activeSessionHolder.getSafeActiveSession()?.also {
@@ -187,8 +178,7 @@ class VectorApplication :
                 }
             }
 
-            @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
-            fun entersBackground() {
+            override fun onPause(owner: LifecycleOwner) {
                 Timber.i("App entered background") // call persistInfo
                 notificationDrawerManager.persistInfo()
                 StateHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder)
@@ -209,9 +199,8 @@ class VectorApplication :
         EmojiManager.install(GoogleEmojiProvider())
     }
 
-    private val startSyncOnFirstStart = object : LifecycleObserver {
-        @OnLifecycleEvent(Lifecycle.Event.ON_START)
-        fun onStart() {
+    private val startSyncOnFirstStart = object : DefaultLifecycleObserver {
+        override fun onStart(owner: LifecycleOwner) {
             Timber.i("App process started")
             authenticationService.getLastAuthenticatedSession()?.startSyncing(appContext)
             ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
@@ -240,10 +229,6 @@ class VectorApplication :
                 .build()
     }
 
-    override fun injector(): VectorComponent {
-        return vectorComponent
-    }
-
     private fun logInfo() {
         val appVersion = versionProvider.getVersion(longFormat = true, useBuildNumber = true)
         val sdkVersion = Matrix.getSdkVersion()
diff --git a/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt b/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt
index f5a5e240c6..f99048501d 100644
--- a/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt
+++ b/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt
@@ -17,10 +17,10 @@
 package im.vector.app.core.contacts
 
 import android.content.Context
-import android.database.Cursor
 import android.net.Uri
 import android.provider.ContactsContract
 import androidx.annotation.WorkerThread
+import im.vector.lib.multipicker.utils.getColumnIndexOrNull
 import timber.log.Timber
 import javax.inject.Inject
 import kotlin.system.measureTimeMillis
@@ -57,16 +57,20 @@ class ContactsDataSource @Inject constructor(
             )
                     ?.use { cursor ->
                         if (cursor.count > 0) {
+                            val idColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Contacts._ID) ?: return@use
+                            val displayNameColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use
+                            val photoUriColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Data.PHOTO_URI)
                             while (cursor.moveToNext()) {
-                                val id = cursor.getLong(ContactsContract.Contacts._ID) ?: continue
-                                val displayName = cursor.getString(ContactsContract.Contacts.DISPLAY_NAME) ?: continue
+                                val id = cursor.getLong(idColumnIndex)
+                                val displayName = cursor.getString(displayNameColumnIndex)
 
                                 val mappedContactBuilder = MappedContactBuilder(
                                         id = id,
                                         displayName = displayName
                                 )
 
-                                cursor.getString(ContactsContract.Data.PHOTO_URI)
+                                photoUriColumnIndex
+                                        ?.let { cursor.getString(it) }
                                         ?.let { Uri.parse(it) }
                                         ?.let { mappedContactBuilder.photoURI = it }
 
@@ -85,12 +89,15 @@ class ContactsDataSource @Inject constructor(
                         null,
                         null,
                         null)
-                        ?.use { innerCursor ->
-                            while (innerCursor.moveToNext()) {
-                                val mappedContactBuilder = innerCursor.getLong(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
-                                        ?.let { map[it] }
+                        ?.use { cursor ->
+                            val idColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Phone.CONTACT_ID) ?: return@use
+                            val phoneNumberColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Phone.NUMBER) ?: return@use
+
+                            while (cursor.moveToNext()) {
+                                val mappedContactBuilder = cursor.getLong(idColumnIndex)
+                                        .let { map[it] }
                                         ?: continue
-                                innerCursor.getString(ContactsContract.CommonDataKinds.Phone.NUMBER)
+                                cursor.getString(phoneNumberColumnIndex)
                                         ?.let {
                                             mappedContactBuilder.msisdns.add(
                                                     MappedMsisdn(
@@ -114,14 +121,17 @@ class ContactsDataSource @Inject constructor(
                         null,
                         null,
                         null)
-                        ?.use { innerCursor ->
-                            while (innerCursor.moveToNext()) {
+                        ?.use { cursor ->
+                            val idColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Email.CONTACT_ID) ?: return@use
+                            val emailColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Email.DATA) ?: return@use
+
+                            while (cursor.moveToNext()) {
                                 // This would allow you get several email addresses
                                 // if the email addresses were stored in an array
-                                val mappedContactBuilder = innerCursor.getLong(ContactsContract.CommonDataKinds.Email.CONTACT_ID)
-                                        ?.let { map[it] }
+                                val mappedContactBuilder = cursor.getLong(idColumnIndex)
+                                        .let { map[it] }
                                         ?: continue
-                                innerCursor.getString(ContactsContract.CommonDataKinds.Email.DATA)
+                                cursor.getString(emailColumnIndex)
                                         ?.let {
                                             mappedContactBuilder.emails.add(
                                                     MappedEmail(
@@ -140,16 +150,4 @@ class ContactsDataSource @Inject constructor(
                 .filter { it.emails.isNotEmpty() || it.msisdns.isNotEmpty() }
                 .map { it.build() }
     }
-
-    private fun Cursor.getString(column: String): String? {
-        return getColumnIndex(column)
-                .takeIf { it != -1 }
-                ?.let { getString(it) }
-    }
-
-    private fun Cursor.getLong(column: String): Long? {
-        return getColumnIndex(column)
-                .takeIf { it != -1 }
-                ?.let { getLong(it) }
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
index e739cac95f..6b7b5f7f62 100644
--- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
@@ -18,6 +18,7 @@ package im.vector.app.core.di
 
 import arrow.core.Option
 import im.vector.app.ActiveSessionDataSource
+import im.vector.app.core.services.GuardServiceStarter
 import im.vector.app.features.call.webrtc.WebRtcCallManager
 import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
 import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
@@ -36,7 +37,8 @@ class ActiveSessionHolder @Inject constructor(private val sessionObservableStore
                                               private val callManager: WebRtcCallManager,
                                               private val pushRuleTriggerListener: PushRuleTriggerListener,
                                               private val sessionListener: SessionListener,
-                                              private val imageManager: ImageManager
+                                              private val imageManager: ImageManager,
+                                              private val guardServiceStarter: GuardServiceStarter
 ) {
 
     private var activeSession: AtomicReference<Session?> = AtomicReference()
@@ -52,6 +54,7 @@ class ActiveSessionHolder @Inject constructor(private val sessionObservableStore
         pushRuleTriggerListener.startWithSession(session)
         session.callSignalingService().addCallListener(callManager)
         imageManager.onSessionStarted(session)
+        guardServiceStarter.start()
     }
 
     fun clearActiveSession() {
diff --git a/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt b/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt
new file mode 100644
index 0000000000..c5f7317ebe
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/di/ActivityEntryPoint.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.di
+
+import androidx.fragment.app.FragmentFactory
+import androidx.lifecycle.ViewModelProvider
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+
+@InstallIn(ActivityComponent::class)
+@EntryPoint
+interface ActivityEntryPoint {
+    fun fragmentFactory(): FragmentFactory
+    fun viewModelFactory(): ViewModelProvider.Factory
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
index e9ec94ebf9..b032f6aa29 100644
--- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
@@ -21,6 +21,8 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentFactory
 import dagger.Binds
 import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
 import dagger.multibindings.IntoMap
 import im.vector.app.features.attachments.preview.AttachmentsPreviewFragment
 import im.vector.app.features.contactsbook.ContactsBookFragment
@@ -92,6 +94,7 @@ import im.vector.app.features.login2.terms.LoginTermsFragment2
 import im.vector.app.features.matrixto.MatrixToRoomSpaceFragment
 import im.vector.app.features.matrixto.MatrixToUserFragment
 import im.vector.app.features.pin.PinFragment
+import im.vector.app.features.poll.create.CreatePollFragment
 import im.vector.app.features.qrcode.QrCodeScannerFragment
 import im.vector.app.features.reactions.EmojiChooserFragment
 import im.vector.app.features.reactions.EmojiSearchResultFragment
@@ -109,8 +112,8 @@ import im.vector.app.features.roomprofile.members.RoomMemberListFragment
 import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsFragment
 import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
 import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
-import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleChooseRestrictedFragment
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleFragment
+import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedFragment
 import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
 import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment
 import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment
@@ -158,6 +161,7 @@ import im.vector.app.features.usercode.ShowUserCodeFragment
 import im.vector.app.features.userdirectory.UserListFragment
 import im.vector.app.features.widgets.WidgetFragment
 
+@InstallIn(ActivityComponent::class)
 @Module
 interface FragmentModule {
     /**
@@ -840,4 +844,9 @@ interface FragmentModule {
     @IntoMap
     @FragmentKey(SpaceLeaveAdvancedFragment::class)
     fun bindSpaceLeaveAdvancedFragment(fragment: SpaceLeaveAdvancedFragment): Fragment
+
+    @Binds
+    @IntoMap
+    @FragmentKey(CreatePollFragment::class)
+    fun bindCreatePollFragment(fragment: CreatePollFragment): Fragment
 }
diff --git a/vector/src/main/java/im/vector/app/core/di/HiltMavericksViewModelFactory.kt b/vector/src/main/java/im/vector/app/core/di/HiltMavericksViewModelFactory.kt
new file mode 100644
index 0000000000..13702053e8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/di/HiltMavericksViewModelFactory.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.di
+
+import com.airbnb.mvrx.MavericksState
+import com.airbnb.mvrx.MavericksViewModel
+import com.airbnb.mvrx.MavericksViewModelFactory
+import com.airbnb.mvrx.ViewModelContext
+import dagger.hilt.DefineComponent
+import dagger.hilt.EntryPoint
+import dagger.hilt.EntryPoints
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+
+/**
+ * To connect Mavericks ViewModel creation with Hilt's dependency injection, add the following Factory and companion object to your MavericksViewModel.
+ *
+ * Example:
+ *
+ * class MyViewModel @AssistedInject constructor(...): MavericksViewModel<MyState>(...) {
+ *
+ *   @AssistedFactory
+ *   interface Factory : AssistedViewModelFactory<MyViewModel, MyState> {
+ *     ...
+ *   }
+ *
+ *   companion object : MavericksViewModelFactory<MyViewModel, MyState> by hiltMavericksViewModelFactory()
+ * }
+ */
+
+inline fun <reified VM : MavericksViewModel<S>, S : MavericksState> hiltMavericksViewModelFactory() = HiltMavericksViewModelFactory<VM, S>(VM::class.java)
+
+class HiltMavericksViewModelFactory<VM : MavericksViewModel<S>, S : MavericksState>(
+    private val viewModelClass: Class<out MavericksViewModel<S>>
+) : MavericksViewModelFactory<VM, S> {
+
+    override fun create(viewModelContext: ViewModelContext, state: S): VM {
+        // We want to create the ViewModelComponent. In order to do that, we need to get its parent: ActivityComponent.
+        val componentBuilder = EntryPoints.get(viewModelContext.app(), CreateMavericksViewModelComponent::class.java).mavericksViewModelComponentBuilder()
+        val viewModelComponent = componentBuilder.build()
+        val viewModelFactoryMap = EntryPoints.get(viewModelComponent, HiltMavericksEntryPoint::class.java).viewModelFactories
+        val viewModelFactory = viewModelFactoryMap[viewModelClass]
+
+        @Suppress("UNCHECKED_CAST")
+        val castedViewModelFactory = viewModelFactory as? MavericksAssistedViewModelFactory<VM, S>
+        return castedViewModelFactory?.create(state) as VM
+    }
+
+    override fun initialState(viewModelContext: ViewModelContext): S? {
+        return super.initialState(viewModelContext)
+    }
+}
+
+/**
+ * Hilt's ViewModelComponent's parent is ActivityRetainedComponent but there is no easy way to access it. SingletonComponent should be sufficient
+ * because the ViewModel that gets created is the only object with a reference to the created component so the lifecycle of it will
+ * still be correct.
+ */
+@MavericksViewModelScoped
+@DefineComponent(parent = SingletonComponent::class)
+interface MavericksViewModelComponent
+
+@DefineComponent.Builder
+interface MavericksViewModelComponentBuilder {
+    fun build(): MavericksViewModelComponent
+}
+
+@EntryPoint
+@InstallIn(SingletonComponent::class)
+interface CreateMavericksViewModelComponent {
+    fun mavericksViewModelComponentBuilder(): MavericksViewModelComponentBuilder
+}
+
+@EntryPoint
+@InstallIn(MavericksViewModelComponent::class)
+interface HiltMavericksEntryPoint {
+    val viewModelFactories: Map<Class<out MavericksViewModel<*>>, MavericksAssistedViewModelFactory<*, *>>
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/HomeModule.kt b/vector/src/main/java/im/vector/app/core/di/HomeModule.kt
new file mode 100644
index 0000000000..1af67cdc83
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/di/HomeModule.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.di
+
+import android.os.Handler
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import im.vector.app.features.home.room.detail.timeline.TimelineEventControllerHandler
+import im.vector.app.features.home.room.detail.timeline.helper.TimelineAsyncHelper
+
+@Module
+@InstallIn(ActivityComponent::class)
+object HomeModule {
+    @Provides
+    @JvmStatic
+    @TimelineEventControllerHandler
+    fun providesTimelineBackgroundHandler(): Handler {
+        return TimelineAsyncHelper.getBackgroundHandler()
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksAssistedViewModelFactory.kt b/vector/src/main/java/im/vector/app/core/di/MavericksAssistedViewModelFactory.kt
new file mode 100644
index 0000000000..7cd6245d64
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksAssistedViewModelFactory.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.di
+
+import com.airbnb.mvrx.MavericksState
+import com.airbnb.mvrx.MavericksViewModel
+
+/**
+ * This factory allows Mavericks to supply the initial or restored [MavericksState] to Hilt.
+ *
+ * Add this interface inside of your [MavericksViewModel] class then create the following Hilt module:
+ *
+ * @Module
+ * @InstallIn(MavericksViewModelComponent::class)
+ * interface ViewModelsModule {
+ *   @Binds
+ *   @IntoMap
+ *   @ViewModelKey(MyViewModel::class)
+ *   fun myViewModelFactory(factory: MyViewModel.Factory): AssistedViewModelFactory<*, *>
+ * }
+ *
+ * If you already have a ViewModelsModule then all you have to do is add the multibinding entry for your new [MavericksViewModel].
+ */
+interface MavericksAssistedViewModelFactory<VM : MavericksViewModel<S>, S : MavericksState> {
+    fun create(initialState: S): VM
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
new file mode 100644
index 0000000000..c827bd0b35
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.di
+
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.multibindings.IntoMap
+import im.vector.app.features.auth.ReAuthViewModel
+import im.vector.app.features.call.VectorCallViewModel
+import im.vector.app.features.call.conference.JitsiCallViewModel
+import im.vector.app.features.call.transfer.CallTransferViewModel
+import im.vector.app.features.contactsbook.ContactsBookViewModel
+import im.vector.app.features.createdirect.CreateDirectRoomViewModel
+import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsViewModel
+import im.vector.app.features.crypto.quads.SharedSecureStorageViewModel
+import im.vector.app.features.crypto.recover.BootstrapSharedViewModel
+import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
+import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodViewModel
+import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeViewModel
+import im.vector.app.features.devtools.RoomDevToolViewModel
+import im.vector.app.features.discovery.DiscoverySettingsViewModel
+import im.vector.app.features.discovery.change.SetIdentityServerViewModel
+import im.vector.app.features.home.HomeActivityViewModel
+import im.vector.app.features.home.HomeDetailViewModel
+import im.vector.app.features.home.PromoteRestrictedViewModel
+import im.vector.app.features.home.UnknownDeviceDetectorSharedViewModel
+import im.vector.app.features.home.UnreadMessagesSharedViewModel
+import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsViewModel
+import im.vector.app.features.home.room.detail.composer.TextComposerViewModel
+import im.vector.app.features.home.room.detail.search.SearchViewModel
+import im.vector.app.features.home.room.detail.timeline.action.MessageActionsViewModel
+import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryViewModel
+import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsViewModel
+import im.vector.app.features.home.room.detail.upgrade.MigrateRoomViewModel
+import im.vector.app.features.home.room.list.RoomListViewModel
+import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
+import im.vector.app.features.invite.InviteUsersToRoomViewModel
+import im.vector.app.features.login.LoginViewModel
+import im.vector.app.features.login2.LoginViewModel2
+import im.vector.app.features.login2.created.AccountCreatedViewModel
+import im.vector.app.features.matrixto.MatrixToBottomSheetViewModel
+import im.vector.app.features.poll.create.CreatePollViewModel
+import im.vector.app.features.rageshake.BugReportViewModel
+import im.vector.app.features.reactions.EmojiSearchResultViewModel
+import im.vector.app.features.room.RequireActiveMembershipViewModel
+import im.vector.app.features.roomdirectory.RoomDirectoryViewModel
+import im.vector.app.features.roomdirectory.createroom.CreateRoomViewModel
+import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerViewModel
+import im.vector.app.features.roomdirectory.roompreview.RoomPreviewViewModel
+import im.vector.app.features.roommemberprofile.RoomMemberProfileViewModel
+import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheetViewModel
+import im.vector.app.features.roomprofile.RoomProfileViewModel
+import im.vector.app.features.roomprofile.alias.RoomAliasViewModel
+import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetViewModel
+import im.vector.app.features.roomprofile.banned.RoomBannedMemberListViewModel
+import im.vector.app.features.roomprofile.members.RoomMemberListViewModel
+import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsViewModel
+import im.vector.app.features.roomprofile.permissions.RoomPermissionsViewModel
+import im.vector.app.features.roomprofile.settings.RoomSettingsViewModel
+import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedViewModel
+import im.vector.app.features.roomprofile.uploads.RoomUploadsViewModel
+import im.vector.app.features.settings.account.deactivation.DeactivateAccountViewModel
+import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewModel
+import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
+import im.vector.app.features.settings.devices.DevicesViewModel
+import im.vector.app.features.settings.devtools.AccountDataViewModel
+import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel
+import im.vector.app.features.settings.devtools.KeyRequestListViewModel
+import im.vector.app.features.settings.devtools.KeyRequestViewModel
+import im.vector.app.features.settings.homeserver.HomeserverSettingsViewModel
+import im.vector.app.features.settings.ignored.IgnoredUsersViewModel
+import im.vector.app.features.settings.locale.LocalePickerViewModel
+import im.vector.app.features.settings.push.PushGatewaysViewModel
+import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel
+import im.vector.app.features.share.IncomingShareViewModel
+import im.vector.app.features.signout.soft.SoftLogoutViewModel
+import im.vector.app.features.spaces.SpaceListViewModel
+import im.vector.app.features.spaces.SpaceMenuViewModel
+import im.vector.app.features.spaces.create.CreateSpaceViewModel
+import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel
+import im.vector.app.features.spaces.invite.SpaceInviteBottomSheetViewModel
+import im.vector.app.features.spaces.leave.SpaceLeaveAdvancedViewModel
+import im.vector.app.features.spaces.manage.SpaceAddRoomsViewModel
+import im.vector.app.features.spaces.manage.SpaceManageRoomsViewModel
+import im.vector.app.features.spaces.manage.SpaceManageSharedViewModel
+import im.vector.app.features.spaces.people.SpacePeopleViewModel
+import im.vector.app.features.spaces.preview.SpacePreviewViewModel
+import im.vector.app.features.spaces.share.ShareSpaceViewModel
+import im.vector.app.features.terms.ReviewTermsViewModel
+import im.vector.app.features.usercode.UserCodeSharedViewModel
+import im.vector.app.features.userdirectory.UserListViewModel
+import im.vector.app.features.widgets.WidgetViewModel
+import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewModel
+import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
+import im.vector.app.features.workers.signout.SignoutCheckViewModel
+
+@InstallIn(MavericksViewModelComponent::class)
+@Module
+interface MavericksViewModelModule {
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomListViewModel::class)
+    fun roomListViewModelFactory(factory: RoomListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceManageRoomsViewModel::class)
+    fun spaceManageRoomsViewModelFactory(factory: SpaceManageRoomsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceManageSharedViewModel::class)
+    fun spaceManageSharedViewModelFactory(factory: SpaceManageSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceListViewModel::class)
+    fun spaceListViewModelFactory(factory: SpaceListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ReAuthViewModel::class)
+    fun reAuthViewModelFactory(factory: ReAuthViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(VectorCallViewModel::class)
+    fun vectorCallViewModelFactory(factory: VectorCallViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(JitsiCallViewModel::class)
+    fun jitsiCallViewModelFactory(factory: JitsiCallViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomDirectoryViewModel::class)
+    fun roomDirectoryViewModelFactory(factory: RoomDirectoryViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ViewReactionsViewModel::class)
+    fun viewReactionsViewModelFactory(factory: ViewReactionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomWidgetPermissionViewModel::class)
+    fun roomWidgetPermissionViewModelFactory(factory: RoomWidgetPermissionViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(WidgetViewModel::class)
+    fun widgetViewModelFactory(factory: WidgetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ServerBackupStatusViewModel::class)
+    fun serverBackupStatusViewModelFactory(factory: ServerBackupStatusViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SignoutCheckViewModel::class)
+    fun signoutCheckViewModelFactory(factory: SignoutCheckViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomDirectoryPickerViewModel::class)
+    fun roomDirectoryPickerViewModelFactory(factory: RoomDirectoryPickerViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomDevToolViewModel::class)
+    fun roomDevToolViewModelFactory(factory: RoomDevToolViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(MigrateRoomViewModel::class)
+    fun migrateRoomViewModelFactory(factory: MigrateRoomViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(IgnoredUsersViewModel::class)
+    fun ignoredUsersViewModelFactory(factory: IgnoredUsersViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(CallTransferViewModel::class)
+    fun callTransferViewModelFactory(factory: CallTransferViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ContactsBookViewModel::class)
+    fun contactsBookViewModelFactory(factory: ContactsBookViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(CreateDirectRoomViewModel::class)
+    fun createDirectRoomViewModelFactory(factory: CreateDirectRoomViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomNotificationSettingsViewModel::class)
+    fun roomNotificationSettingsViewModelFactory(factory: RoomNotificationSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(KeysBackupSettingsViewModel::class)
+    fun keysBackupSettingsViewModelFactory(factory: KeysBackupSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SharedSecureStorageViewModel::class)
+    fun sharedSecureStorageViewModelFactory(factory: SharedSecureStorageViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(PromoteRestrictedViewModel::class)
+    fun promoteRestrictedViewModelFactory(factory: PromoteRestrictedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(UserListViewModel::class)
+    fun userListViewModelFactory(factory: UserListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(UserCodeSharedViewModel::class)
+    fun userCodeSharedViewModelFactory(factory: UserCodeSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ReviewTermsViewModel::class)
+    fun reviewTermsViewModelFactory(factory: ReviewTermsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ShareSpaceViewModel::class)
+    fun shareSpaceViewModelFactory(factory: ShareSpaceViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpacePreviewViewModel::class)
+    fun spacePreviewViewModelFactory(factory: SpacePreviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpacePeopleViewModel::class)
+    fun spacePeopleViewModelFactory(factory: SpacePeopleViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceAddRoomsViewModel::class)
+    fun spaceAddRoomsViewModelFactory(factory: SpaceAddRoomsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceLeaveAdvancedViewModel::class)
+    fun spaceLeaveAdvancedViewModelFactory(factory: SpaceLeaveAdvancedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceInviteBottomSheetViewModel::class)
+    fun spaceInviteBottomSheetViewModelFactory(factory: SpaceInviteBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceDirectoryViewModel::class)
+    fun spaceDirectoryViewModelFactory(factory: SpaceDirectoryViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(CreateSpaceViewModel::class)
+    fun createSpaceViewModelFactory(factory: CreateSpaceViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SpaceMenuViewModel::class)
+    fun spaceMenuViewModelFactory(factory: SpaceMenuViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SoftLogoutViewModel::class)
+    fun softLogoutViewModelFactory(factory: SoftLogoutViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(IncomingShareViewModel::class)
+    fun incomingShareViewModelFactory(factory: IncomingShareViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ThreePidsSettingsViewModel::class)
+    fun threePidsSettingsViewModelFactory(factory: ThreePidsSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(PushGatewaysViewModel::class)
+    fun pushGatewaysViewModelFactory(factory: PushGatewaysViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(HomeserverSettingsViewModel::class)
+    fun homeserverSettingsViewModelFactory(factory: HomeserverSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(LocalePickerViewModel::class)
+    fun localePickerViewModelFactory(factory: LocalePickerViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(GossipingEventsPaperTrailViewModel::class)
+    fun gossipingEventsPaperTrailViewModelFactory(factory: GossipingEventsPaperTrailViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(AccountDataViewModel::class)
+    fun accountDataViewModelFactory(factory: AccountDataViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(DevicesViewModel::class)
+    fun devicesViewModelFactory(factory: DevicesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(KeyRequestListViewModel::class)
+    fun keyRequestListViewModelFactory(factory: KeyRequestListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(KeyRequestViewModel::class)
+    fun keyRequestViewModelFactory(factory: KeyRequestViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(CrossSigningSettingsViewModel::class)
+    fun crossSigningSettingsViewModelFactory(factory: CrossSigningSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(DeactivateAccountViewModel::class)
+    fun deactivateAccountViewModelFactory(factory: DeactivateAccountViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomUploadsViewModel::class)
+    fun roomUploadsViewModelFactory(factory: RoomUploadsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomJoinRuleChooseRestrictedViewModel::class)
+    fun roomJoinRuleChooseRestrictedViewModelFactory(factory: RoomJoinRuleChooseRestrictedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomSettingsViewModel::class)
+    fun roomSettingsViewModelFactory(factory: RoomSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomPermissionsViewModel::class)
+    fun roomPermissionsViewModelFactory(factory: RoomPermissionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomMemberListViewModel::class)
+    fun roomMemberListViewModelFactory(factory: RoomMemberListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomBannedMemberListViewModel::class)
+    fun roomBannedMemberListViewModelFactory(factory: RoomBannedMemberListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomAliasViewModel::class)
+    fun roomAliasViewModelFactory(factory: RoomAliasViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomAliasBottomSheetViewModel::class)
+    fun roomAliasBottomSheetViewModelFactory(factory: RoomAliasBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomProfileViewModel::class)
+    fun roomProfileViewModelFactory(factory: RoomProfileViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomMemberProfileViewModel::class)
+    fun roomMemberProfileViewModelFactory(factory: RoomMemberProfileViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RoomPreviewViewModel::class)
+    fun roomPreviewViewModelFactory(factory: RoomPreviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(CreateRoomViewModel::class)
+    fun createRoomViewModelFactory(factory: CreateRoomViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(RequireActiveMembershipViewModel::class)
+    fun requireActiveMembershipViewModelFactory(factory: RequireActiveMembershipViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(EmojiSearchResultViewModel::class)
+    fun emojiSearchResultViewModelFactory(factory: EmojiSearchResultViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(BugReportViewModel::class)
+    fun bugReportViewModelFactory(factory: BugReportViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(MatrixToBottomSheetViewModel::class)
+    fun matrixToBottomSheetViewModelFactory(factory: MatrixToBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(AccountCreatedViewModel::class)
+    fun accountCreatedViewModelFactory(factory: AccountCreatedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(LoginViewModel2::class)
+    fun loginViewModel2Factory(factory: LoginViewModel2.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(LoginViewModel::class)
+    fun loginViewModelFactory(factory: LoginViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(HomeServerCapabilitiesViewModel::class)
+    fun homeServerCapabilitiesViewModelFactory(factory: HomeServerCapabilitiesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(InviteUsersToRoomViewModel::class)
+    fun inviteUsersToRoomViewModelFactory(factory: InviteUsersToRoomViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(ViewEditHistoryViewModel::class)
+    fun viewEditHistoryViewModelFactory(factory: ViewEditHistoryViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(MessageActionsViewModel::class)
+    fun messageActionsViewModelFactory(factory: MessageActionsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(VerificationChooseMethodViewModel::class)
+    fun verificationChooseMethodViewModelFactory(factory: VerificationChooseMethodViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(VerificationEmojiCodeViewModel::class)
+    fun verificationEmojiCodeViewModelFactory(factory: VerificationEmojiCodeViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SearchViewModel::class)
+    fun searchViewModelFactory(factory: SearchViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(UnreadMessagesSharedViewModel::class)
+    fun unreadMessagesSharedViewModelFactory(factory: UnreadMessagesSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(UnknownDeviceDetectorSharedViewModel::class)
+    fun unknownDeviceDetectorSharedViewModelFactory(factory: UnknownDeviceDetectorSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(DiscoverySettingsViewModel::class)
+    fun discoverySettingsViewModelFactory(factory: DiscoverySettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(TextComposerViewModel::class)
+    fun textComposerViewModelFactory(factory: TextComposerViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(SetIdentityServerViewModel::class)
+    fun setIdentityServerViewModelFactory(factory: SetIdentityServerViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(BreadcrumbsViewModel::class)
+    fun breadcrumbsViewModelFactory(factory: BreadcrumbsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(HomeDetailViewModel::class)
+    fun homeDetailViewModelFactory(factory: HomeDetailViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(DeviceVerificationInfoBottomSheetViewModel::class)
+    fun deviceVerificationInfoBottomSheetViewModelFactory(factory: DeviceVerificationInfoBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(DeviceListBottomSheetViewModel::class)
+    fun deviceListBottomSheetViewModelFactory(factory: DeviceListBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(HomeActivityViewModel::class)
+    fun homeActivityViewModelFactory(factory: HomeActivityViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(BootstrapSharedViewModel::class)
+    fun bootstrapSharedViewModelFactory(factory: BootstrapSharedViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(VerificationBottomSheetViewModel::class)
+    fun verificationBottomSheetViewModelFactory(factory: VerificationBottomSheetViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(CreatePollViewModel::class)
+    fun createPollViewModelFactory(factory: CreatePollViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenScope.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelScoped.kt
similarity index 71%
rename from vector/src/main/java/im/vector/app/core/di/ScreenScope.kt
rename to vector/src/main/java/im/vector/app/core/di/MavericksViewModelScoped.kt
index c39d6a947e..58b9246fe5 100644
--- a/vector/src/main/java/im/vector/app/core/di/ScreenScope.kt
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelScoped.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019 New Vector Ltd
+ * Copyright (c) 2021 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,7 +18,8 @@ package im.vector.app.core.di
 
 import javax.inject.Scope
 
+/**
+ * Scope annotation for bindings that should exist for the life of an MavericksViewModel.
+ */
 @Scope
-@MustBeDocumented
-@Retention(AnnotationRetention.RUNTIME)
-annotation class ScreenScope
+annotation class MavericksViewModelScoped
diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt
deleted file mode 100644
index 76b511d2bd..0000000000
--- a/vector/src/main/java/im/vector/app/core/di/ScreenComponent.kt
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.core.di
-
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.FragmentFactory
-import androidx.lifecycle.ViewModelProvider
-import dagger.BindsInstance
-import dagger.Component
-import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
-import im.vector.app.core.error.ErrorFormatter
-import im.vector.app.core.preference.UserAvatarPreference
-import im.vector.app.features.MainActivity
-import im.vector.app.features.auth.ReAuthActivity
-import im.vector.app.features.call.CallControlsBottomSheet
-import im.vector.app.features.call.VectorCallActivity
-import im.vector.app.features.call.conference.VectorJitsiActivity
-import im.vector.app.features.call.transfer.CallTransferActivity
-import im.vector.app.features.createdirect.CreateDirectRoomActivity
-import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity
-import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
-import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
-import im.vector.app.features.crypto.recover.BootstrapBottomSheet
-import im.vector.app.features.crypto.verification.VerificationBottomSheet
-import im.vector.app.features.debug.DebugMenuActivity
-import im.vector.app.features.devtools.RoomDevToolActivity
-import im.vector.app.features.home.HomeActivity
-import im.vector.app.features.home.HomeModule
-import im.vector.app.features.home.room.detail.JoinReplacementRoomBottomSheet
-import im.vector.app.features.home.room.detail.RoomDetailActivity
-import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
-import im.vector.app.features.home.room.detail.search.SearchActivity
-import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet
-import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
-import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
-import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet
-import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
-import im.vector.app.features.home.room.filtered.FilteredRoomsActivity
-import im.vector.app.features.home.room.list.RoomListModule
-import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
-import im.vector.app.features.invite.AutoAcceptInvites
-import im.vector.app.features.invite.InviteUsersToRoomActivity
-import im.vector.app.features.invite.VectorInviteView
-import im.vector.app.features.link.LinkHandlerActivity
-import im.vector.app.features.login.LoginActivity
-import im.vector.app.features.login2.LoginActivity2
-import im.vector.app.features.matrixto.MatrixToBottomSheet
-import im.vector.app.features.media.BigImageViewerActivity
-import im.vector.app.features.media.VectorAttachmentViewerActivity
-import im.vector.app.features.navigation.Navigator
-import im.vector.app.features.pin.PinLocker
-import im.vector.app.features.qrcode.QrCodeScannerActivity
-import im.vector.app.features.rageshake.BugReportActivity
-import im.vector.app.features.rageshake.BugReporter
-import im.vector.app.features.rageshake.RageShake
-import im.vector.app.features.reactions.EmojiReactionPickerActivity
-import im.vector.app.features.reactions.widget.ReactionButton
-import im.vector.app.features.roomdirectory.RoomDirectoryActivity
-import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
-import im.vector.app.features.roommemberprofile.RoomMemberProfileActivity
-import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
-import im.vector.app.features.roomprofile.RoomProfileActivity
-import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheet
-import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistoryVisibilityBottomSheet
-import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleActivity
-import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleBottomSheet
-import im.vector.app.features.settings.VectorSettingsActivity
-import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheet
-import im.vector.app.features.share.IncomingShareActivity
-import im.vector.app.features.signout.soft.SoftLogoutActivity
-import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet
-import im.vector.app.features.spaces.LeaveSpaceBottomSheet
-import im.vector.app.features.spaces.SpaceCreationActivity
-import im.vector.app.features.spaces.SpaceExploreActivity
-import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
-import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
-import im.vector.app.features.spaces.leave.SpaceLeaveAdvancedActivity
-import im.vector.app.features.spaces.manage.SpaceManageActivity
-import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
-import im.vector.app.features.terms.ReviewTermsActivity
-import im.vector.app.features.ui.UiStateRepository
-import im.vector.app.features.usercode.UserCodeActivity
-import im.vector.app.features.widgets.WidgetActivity
-import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
-import im.vector.app.features.workers.signout.SignOutBottomSheetDialogFragment
-import kotlinx.coroutines.CoroutineScope
-
-@Component(
-        dependencies = [
-            VectorComponent::class
-        ],
-        modules = [
-            ViewModelModule::class,
-            FragmentModule::class,
-            HomeModule::class,
-            RoomListModule::class,
-            ScreenModule::class
-        ]
-)
-@ScreenScope
-interface ScreenComponent {
-
-    /* ==========================================================================================
-     * Shortcut to VectorComponent elements
-     * ========================================================================================== */
-
-    fun activeSessionHolder(): ActiveSessionHolder
-    fun fragmentFactory(): FragmentFactory
-    fun viewModelFactory(): ViewModelProvider.Factory
-    fun bugReporter(): BugReporter
-    fun rageShake(): RageShake
-    fun navigator(): Navigator
-    fun pinLocker(): PinLocker
-    fun errorFormatter(): ErrorFormatter
-    fun uiStateRepository(): UiStateRepository
-    fun unrecognizedCertificateDialog(): UnrecognizedCertificateDialog
-    fun autoAcceptInvites(): AutoAcceptInvites
-    fun appCoroutineScope(): CoroutineScope
-
-    /* ==========================================================================================
-     * Activities
-     * ========================================================================================== */
-
-    fun inject(activity: HomeActivity)
-    fun inject(activity: RoomDetailActivity)
-    fun inject(activity: RoomProfileActivity)
-    fun inject(activity: RoomMemberProfileActivity)
-    fun inject(activity: VectorSettingsActivity)
-    fun inject(activity: KeysBackupManageActivity)
-    fun inject(activity: EmojiReactionPickerActivity)
-    fun inject(activity: LoginActivity)
-    fun inject(activity: LoginActivity2)
-    fun inject(activity: LinkHandlerActivity)
-    fun inject(activity: MainActivity)
-    fun inject(activity: RoomDirectoryActivity)
-    fun inject(activity: KeysBackupSetupActivity)
-    fun inject(activity: BugReportActivity)
-    fun inject(activity: FilteredRoomsActivity)
-    fun inject(activity: CreateRoomActivity)
-    fun inject(activity: CreateDirectRoomActivity)
-    fun inject(activity: IncomingShareActivity)
-    fun inject(activity: SoftLogoutActivity)
-    fun inject(activity: QrCodeScannerActivity)
-    fun inject(activity: DebugMenuActivity)
-    fun inject(activity: SharedSecureStorageActivity)
-    fun inject(activity: BigImageViewerActivity)
-    fun inject(activity: InviteUsersToRoomActivity)
-    fun inject(activity: ReviewTermsActivity)
-    fun inject(activity: WidgetActivity)
-    fun inject(activity: VectorCallActivity)
-    fun inject(activity: VectorAttachmentViewerActivity)
-    fun inject(activity: VectorJitsiActivity)
-    fun inject(activity: SearchActivity)
-    fun inject(activity: UserCodeActivity)
-    fun inject(activity: CallTransferActivity)
-    fun inject(activity: ReAuthActivity)
-    fun inject(activity: RoomDevToolActivity)
-    fun inject(activity: SpaceCreationActivity)
-    fun inject(activity: SpaceExploreActivity)
-    fun inject(activity: SpaceManageActivity)
-    fun inject(activity: RoomJoinRuleActivity)
-    fun inject(activity: SpaceLeaveAdvancedActivity)
-
-    /* ==========================================================================================
-     * BottomSheets
-     * ========================================================================================== */
-
-    fun inject(bottomSheet: MessageActionsBottomSheet)
-    fun inject(bottomSheet: ViewReactionsBottomSheet)
-    fun inject(bottomSheet: ViewEditHistoryBottomSheet)
-    fun inject(bottomSheet: DisplayReadReceiptsBottomSheet)
-    fun inject(bottomSheet: RoomListQuickActionsBottomSheet)
-    fun inject(bottomSheet: RoomAliasBottomSheet)
-    fun inject(bottomSheet: RoomHistoryVisibilityBottomSheet)
-    fun inject(bottomSheet: RoomJoinRuleBottomSheet)
-    fun inject(bottomSheet: VerificationBottomSheet)
-    fun inject(bottomSheet: DeviceVerificationInfoBottomSheet)
-    fun inject(bottomSheet: DeviceListBottomSheet)
-    fun inject(bottomSheet: BootstrapBottomSheet)
-    fun inject(bottomSheet: RoomWidgetPermissionBottomSheet)
-    fun inject(bottomSheet: RoomWidgetsBottomSheet)
-    fun inject(bottomSheet: CallControlsBottomSheet)
-    fun inject(bottomSheet: SignOutBottomSheetDialogFragment)
-    fun inject(bottomSheet: MatrixToBottomSheet)
-    fun inject(bottomSheet: ShareSpaceBottomSheet)
-    fun inject(bottomSheet: SpaceSettingsMenuBottomSheet)
-    fun inject(bottomSheet: InviteRoomSpaceChooserBottomSheet)
-    fun inject(bottomSheet: SpaceInviteBottomSheet)
-    fun inject(bottomSheet: JoinReplacementRoomBottomSheet)
-    fun inject(bottomSheet: MigrateRoomBottomSheet)
-    fun inject(bottomSheet: LeaveSpaceBottomSheet)
-
-    /* ==========================================================================================
-     * Others
-     * ========================================================================================== */
-
-    fun inject(view: VectorInviteView)
-    fun inject(preference: UserAvatarPreference)
-    fun inject(button: ReactionButton)
-
-    /* ==========================================================================================
-     * Factory
-     * ========================================================================================== */
-
-    @Component.Factory
-    interface Factory {
-        fun create(vectorComponent: VectorComponent,
-                   @BindsInstance context: AppCompatActivity
-        ): ScreenComponent
-    }
-}
diff --git a/vector/src/main/java/im/vector/app/core/di/ScreenModule.kt b/vector/src/main/java/im/vector/app/core/di/ScreenModule.kt
index 5f50f186d0..2dab05378c 100644
--- a/vector/src/main/java/im/vector/app/core/di/ScreenModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ScreenModule.kt
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019 New Vector Ltd
+ * Copyright (c) 2021 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,9 +20,13 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.recyclerview.widget.RecyclerView
 import dagger.Module
 import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.scopes.ActivityScoped
 import im.vector.app.core.glide.GlideApp
 
 @Module
+@InstallIn(ActivityComponent::class)
 object ScreenModule {
 
     @Provides
@@ -31,6 +35,6 @@ object ScreenModule {
 
     @Provides
     @JvmStatic
-    @ScreenScope
+    @ActivityScoped
     fun providesSharedViewPool() = RecyclerView.RecycledViewPool()
 }
diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt b/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt
new file mode 100644
index 0000000000..52316751e6
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.di
+
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
+import im.vector.app.core.error.ErrorFormatter
+import im.vector.app.features.call.webrtc.WebRtcCallManager
+import im.vector.app.features.home.AvatarRenderer
+import im.vector.app.features.navigation.Navigator
+import im.vector.app.features.pin.PinLocker
+import im.vector.app.features.rageshake.BugReporter
+import im.vector.app.features.session.SessionListener
+import im.vector.app.features.settings.VectorPreferences
+import im.vector.app.features.ui.UiStateRepository
+import kotlinx.coroutines.CoroutineScope
+
+@InstallIn(SingletonComponent::class)
+@EntryPoint
+interface SingletonEntryPoint {
+
+    fun sessionListener(): SessionListener
+
+    fun avatarRenderer(): AvatarRenderer
+
+    fun activeSessionHolder(): ActiveSessionHolder
+
+    fun unrecognizedCertificateDialog(): UnrecognizedCertificateDialog
+
+    fun navigator(): Navigator
+
+    fun errorFormatter(): ErrorFormatter
+
+    fun bugReporter(): BugReporter
+
+    fun vectorPreferences(): VectorPreferences
+
+    fun uiStateRepository(): UiStateRepository
+
+    fun pinLocker(): PinLocker
+
+    fun webRtcCallManager(): WebRtcCallManager
+
+    fun appCoroutineScope(): CoroutineScope
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/VectorModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt
similarity index 54%
rename from vector/src/main/java/im/vector/app/core/di/VectorModule.kt
rename to vector/src/main/java/im/vector/app/core/di/SingletonModule.kt
index ddb765cef8..a3d8f39b30 100644
--- a/vector/src/main/java/im/vector/app/core/di/VectorModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.core.di
 
+import android.app.Application
 import android.content.Context
 import android.content.Context.MODE_PRIVATE
 import android.content.SharedPreferences
@@ -23,6 +24,8 @@ import android.content.res.Resources
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
 import im.vector.app.core.dispatchers.CoroutineDispatchers
 import im.vector.app.core.error.DefaultErrorFormatter
 import im.vector.app.core.error.ErrorFormatter
@@ -45,74 +48,9 @@ import org.matrix.android.sdk.api.raw.RawService
 import org.matrix.android.sdk.api.session.Session
 import javax.inject.Singleton
 
+@InstallIn(SingletonComponent::class)
 @Module
-abstract class VectorModule {
-
-    @Module
-    companion object {
-
-        @Provides
-        @JvmStatic
-        fun providesResources(context: Context): Resources {
-            return context.resources
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesSharedPreferences(context: Context): SharedPreferences {
-            return context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesMatrix(context: Context): Matrix {
-            return Matrix.getInstance(context)
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesCurrentSession(activeSessionHolder: ActiveSessionHolder): Session {
-            // TODO: handle session injection better
-            return activeSessionHolder.getActiveSession()
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesLegacySessionImporter(matrix: Matrix): LegacySessionImporter {
-            return matrix.legacySessionImporter()
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesAuthenticationService(matrix: Matrix): AuthenticationService {
-            return matrix.authenticationService()
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesRawService(matrix: Matrix): RawService {
-            return matrix.rawService()
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesHomeServerHistoryService(matrix: Matrix): HomeServerHistoryService {
-            return matrix.homeServerHistoryService()
-        }
-
-        @Provides
-        @JvmStatic
-        @Singleton
-        fun providesApplicationCoroutineScope(): CoroutineScope {
-            return CoroutineScope(SupervisorJob() + Dispatchers.Main)
-        }
-
-        @Provides
-        @JvmStatic
-        fun providesCoroutineDispatchers(): CoroutineDispatchers {
-            return CoroutineDispatchers(io = Dispatchers.IO)
-        }
-    }
+abstract class VectorBindModule {
 
     @Binds
     abstract fun bindNavigator(navigator: DefaultNavigator): Navigator
@@ -129,3 +67,76 @@ abstract class VectorModule {
     @Binds
     abstract fun bindAutoAcceptInvites(autoAcceptInvites: CompileTimeAutoAcceptInvites): AutoAcceptInvites
 }
+
+@InstallIn(SingletonComponent::class)
+@Module
+object VectorStaticModule {
+
+    @Provides
+    @JvmStatic
+    fun providesContext(application: Application): Context {
+        return application.applicationContext
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesResources(context: Context): Resources {
+        return context.resources
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesSharedPreferences(context: Context): SharedPreferences {
+        return context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesMatrix(context: Context): Matrix {
+        return Matrix.getInstance(context)
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesCurrentSession(activeSessionHolder: ActiveSessionHolder): Session {
+        // TODO: handle session injection better
+        return activeSessionHolder.getActiveSession()
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesLegacySessionImporter(matrix: Matrix): LegacySessionImporter {
+        return matrix.legacySessionImporter()
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesAuthenticationService(matrix: Matrix): AuthenticationService {
+        return matrix.authenticationService()
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesRawService(matrix: Matrix): RawService {
+        return matrix.rawService()
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesHomeServerHistoryService(matrix: Matrix): HomeServerHistoryService {
+        return matrix.homeServerHistoryService()
+    }
+
+    @Provides
+    @JvmStatic
+    @Singleton
+    fun providesApplicationCoroutineScope(): CoroutineScope {
+        return CoroutineScope(SupervisorJob() + Dispatchers.Main)
+    }
+
+    @Provides
+    @JvmStatic
+    fun providesCoroutineDispatchers(): CoroutineDispatchers {
+        return CoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.Default)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt
deleted file mode 100644
index a8bf128367..0000000000
--- a/vector/src/main/java/im/vector/app/core/di/VectorComponent.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.core.di
-
-import android.content.Context
-import android.content.res.Resources
-import dagger.BindsInstance
-import dagger.Component
-import im.vector.app.ActiveSessionDataSource
-import im.vector.app.AppStateHandler
-import im.vector.app.EmojiCompatFontProvider
-import im.vector.app.EmojiCompatWrapper
-import im.vector.app.VectorApplication
-import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
-import im.vector.app.core.dispatchers.CoroutineDispatchers
-import im.vector.app.core.error.ErrorFormatter
-import im.vector.app.core.network.WifiDetector
-import im.vector.app.core.pushers.PushersManager
-import im.vector.app.core.utils.AssetReader
-import im.vector.app.core.utils.DimensionConverter
-import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
-import im.vector.app.features.call.webrtc.WebRtcCallManager
-import im.vector.app.features.configuration.VectorConfiguration
-import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
-import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
-import im.vector.app.features.home.AvatarRenderer
-import im.vector.app.features.home.CurrentSpaceSuggestedRoomListDataSource
-import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
-import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
-import im.vector.app.features.html.EventHtmlRenderer
-import im.vector.app.features.html.VectorHtmlCompressor
-import im.vector.app.features.invite.AutoAcceptInvites
-import im.vector.app.features.login.ReAuthHelper
-import im.vector.app.features.navigation.Navigator
-import im.vector.app.features.notifications.NotifiableEventResolver
-import im.vector.app.features.notifications.NotificationBroadcastReceiver
-import im.vector.app.features.notifications.NotificationDrawerManager
-import im.vector.app.features.notifications.NotificationUtils
-import im.vector.app.features.notifications.PushRuleTriggerListener
-import im.vector.app.features.pin.PinCodeStore
-import im.vector.app.features.pin.PinLocker
-import im.vector.app.features.popup.PopupAlertManager
-import im.vector.app.features.rageshake.BugReporter
-import im.vector.app.features.rageshake.VectorFileLogger
-import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
-import im.vector.app.features.reactions.data.EmojiDataSource
-import im.vector.app.features.session.SessionListener
-import im.vector.app.features.settings.VectorDataStore
-import im.vector.app.features.settings.VectorPreferences
-import im.vector.app.features.ui.UiStateRepository
-import kotlinx.coroutines.CoroutineScope
-import org.matrix.android.sdk.api.Matrix
-import org.matrix.android.sdk.api.auth.AuthenticationService
-import org.matrix.android.sdk.api.auth.HomeServerHistoryService
-import org.matrix.android.sdk.api.raw.RawService
-import org.matrix.android.sdk.api.session.Session
-import javax.inject.Singleton
-
-@Component(modules = [VectorModule::class])
-@Singleton
-interface VectorComponent {
-
-    fun inject(notificationBroadcastReceiver: NotificationBroadcastReceiver)
-
-    fun inject(vectorApplication: VectorApplication)
-
-    fun matrix(): Matrix
-
-    fun matrixItemColorProvider(): MatrixItemColorProvider
-
-    fun sessionListener(): SessionListener
-
-    fun currentSession(): Session
-
-    fun notificationUtils(): NotificationUtils
-
-    fun notificationDrawerManager(): NotificationDrawerManager
-
-    fun appContext(): Context
-
-    fun resources(): Resources
-
-    fun assetReader(): AssetReader
-
-    fun dimensionConverter(): DimensionConverter
-
-    fun vectorConfiguration(): VectorConfiguration
-
-    fun avatarRenderer(): AvatarRenderer
-
-    fun activeSessionHolder(): ActiveSessionHolder
-
-    fun unrecognizedCertificateDialog(): UnrecognizedCertificateDialog
-
-    fun emojiCompatFontProvider(): EmojiCompatFontProvider
-
-    fun emojiCompatWrapper(): EmojiCompatWrapper
-
-    fun eventHtmlRenderer(): EventHtmlRenderer
-
-    fun vectorHtmlCompressor(): VectorHtmlCompressor
-
-    fun navigator(): Navigator
-
-    fun errorFormatter(): ErrorFormatter
-
-    fun appStateHandler(): AppStateHandler
-
-    fun currentSpaceSuggestedRoomListDataSource(): CurrentSpaceSuggestedRoomListDataSource
-
-    fun roomDetailPendingActionStore(): RoomDetailPendingActionStore
-
-    fun activeSessionObservableStore(): ActiveSessionDataSource
-
-    fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler
-
-    fun incomingKeyRequestHandler(): KeyRequestHandler
-
-    fun authenticationService(): AuthenticationService
-
-    fun rawService(): RawService
-
-    fun homeServerHistoryService(): HomeServerHistoryService
-
-    fun bugReporter(): BugReporter
-
-    fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler
-
-    fun pushRuleTriggerListener(): PushRuleTriggerListener
-
-    fun pusherManager(): PushersManager
-
-    fun notifiableEventResolver(): NotifiableEventResolver
-
-    fun vectorPreferences(): VectorPreferences
-
-    fun vectorDataStore(): VectorDataStore
-
-    fun wifiDetector(): WifiDetector
-
-    fun vectorFileLogger(): VectorFileLogger
-
-    fun uiStateRepository(): UiStateRepository
-
-    fun pinCodeStore(): PinCodeStore
-
-    fun emojiDataSource(): EmojiDataSource
-
-    fun alertManager(): PopupAlertManager
-
-    fun reAuthHelper(): ReAuthHelper
-
-    fun pinLocker(): PinLocker
-
-    fun autoAcceptInvites(): AutoAcceptInvites
-
-    fun webRtcCallManager(): WebRtcCallManager
-
-    fun appCoroutineScope(): CoroutineScope
-
-    fun coroutineDispatchers(): CoroutineDispatchers
-
-    fun jitsiActiveConferenceHolder(): JitsiActiveConferenceHolder
-
-    @Component.Factory
-    interface Factory {
-        fun create(@BindsInstance context: Context): VectorComponent
-    }
-}
diff --git a/vector/src/main/java/im/vector/app/core/di/ViewModelKey.kt b/vector/src/main/java/im/vector/app/core/di/ViewModelKey.kt
index 5f0ee30821..2782edd558 100644
--- a/vector/src/main/java/im/vector/app/core/di/ViewModelKey.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ViewModelKey.kt
@@ -17,6 +17,7 @@
 package im.vector.app.core.di
 
 import androidx.lifecycle.ViewModel
+import com.airbnb.mvrx.MavericksViewModel
 import dagger.MapKey
 import kotlin.reflect.KClass
 
@@ -24,3 +25,8 @@ import kotlin.reflect.KClass
 @Retention(AnnotationRetention.RUNTIME)
 @MapKey
 annotation class ViewModelKey(val value: KClass<out ViewModel>)
+
+@Retention(AnnotationRetention.RUNTIME)
+@Target(AnnotationTarget.FUNCTION)
+@MapKey
+annotation class MavericksViewModelKey(val value: KClass<out MavericksViewModel<*>>)
diff --git a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt
index 4e07c1e2ca..4f8329c026 100644
--- a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt
@@ -20,6 +20,8 @@ import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import dagger.Binds
 import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
 import dagger.multibindings.IntoMap
 import im.vector.app.core.platform.ConfigurationViewModel
 import im.vector.app.features.call.SharedKnownCallsViewModel
@@ -42,6 +44,7 @@ import im.vector.app.features.spaces.SpacePreviewSharedActionViewModel
 import im.vector.app.features.spaces.people.SpacePeopleSharedActionViewModel
 import im.vector.app.features.userdirectory.UserListSharedActionViewModel
 
+@InstallIn(ActivityComponent::class)
 @Module
 interface ViewModelModule {
 
diff --git a/vector/src/main/java/im/vector/app/core/dispatchers/CoroutineDispatchers.kt b/vector/src/main/java/im/vector/app/core/dispatchers/CoroutineDispatchers.kt
index c489290a55..008ca4a9ce 100644
--- a/vector/src/main/java/im/vector/app/core/dispatchers/CoroutineDispatchers.kt
+++ b/vector/src/main/java/im/vector/app/core/dispatchers/CoroutineDispatchers.kt
@@ -19,4 +19,6 @@ package im.vector.app.core.dispatchers
 import kotlinx.coroutines.CoroutineDispatcher
 import javax.inject.Inject
 
-data class CoroutineDispatchers @Inject constructor(val io: CoroutineDispatcher)
+data class CoroutineDispatchers @Inject constructor(
+        val io: CoroutineDispatcher,
+        val computation: CoroutineDispatcher)
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItem.kt
index e6451b34ef..0af342641e 100644
--- a/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItem.kt
+++ b/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItem.kt
@@ -32,6 +32,7 @@ abstract class ProfileMatrixItem : BaseProfileMatrixItem<ProfileMatrixItem.Holde
     open class Holder : VectorEpoxyHolder() {
         val titleView by bind<TextView>(R.id.matrixItemTitle)
         val subtitleView by bind<TextView>(R.id.matrixItemSubtitle)
+        val powerLabel by bind<TextView>(R.id.matrixItemPowerLevelLabel)
         val presenceImageView by bind<PresenceStateImageView>(R.id.matrixItemPresenceImageView)
         val avatarImageView by bind<ImageView>(R.id.matrixItemAvatar)
         val avatarDecorationImageView by bind<ShieldImageView>(R.id.matrixItemAvatarDecoration)
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItemWithPowerLevel.kt b/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItemWithPowerLevel.kt
index b7fd597789..12189dc8f4 100644
--- a/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItemWithPowerLevel.kt
+++ b/vector/src/main/java/im/vector/app/core/epoxy/profiles/ProfileMatrixItemWithPowerLevel.kt
@@ -17,7 +17,6 @@
 
 package im.vector.app.core.epoxy.profiles
 
-import android.widget.TextView
 import androidx.core.view.isVisible
 import com.airbnb.epoxy.EpoxyAttribute
 import com.airbnb.epoxy.EpoxyModelClass
@@ -25,7 +24,7 @@ import im.vector.app.R
 import im.vector.app.core.extensions.setTextOrHide
 
 @EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
-abstract class ProfileMatrixItemWithPowerLevel : BaseProfileMatrixItem<ProfileMatrixItemWithPowerLevel.Holder>() {
+abstract class ProfileMatrixItemWithPowerLevel : ProfileMatrixItem() {
 
     @EpoxyAttribute var powerLevelLabel: CharSequence? = null
 
@@ -34,8 +33,4 @@ abstract class ProfileMatrixItemWithPowerLevel : BaseProfileMatrixItem<ProfileMa
         holder.editableView.isVisible = false
         holder.powerLabel.setTextOrHide(powerLevelLabel)
     }
-
-    class Holder : ProfileMatrixItem.Holder() {
-        val powerLabel by bind<TextView>(R.id.matrixItemPowerLevelLabel)
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt b/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt
index ee3d79d846..dbe90dfdc1 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/BasicExtensions.kt
@@ -66,3 +66,7 @@ fun String?.insertBeforeLast(insert: String, delimiter: String = "."): String {
         replaceRange(idx, idx, insert)
     }
 }
+
+inline fun <reified R> Any?.takeAs(): R? {
+    return takeIf { it is R } as R?
+}
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Context.kt b/vector/src/main/java/im/vector/app/core/extensions/Context.kt
index c1c435edf2..59847da7c9 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Context.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Context.kt
@@ -17,14 +17,9 @@
 package im.vector.app.core.extensions
 
 import android.content.Context
-import im.vector.app.core.di.HasVectorInjector
-import im.vector.app.core.di.VectorComponent
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.SingletonEntryPoint
 
-fun Context.vectorComponent(): VectorComponent {
-    val appContext = applicationContext
-    if (appContext is HasVectorInjector) {
-        return appContext.injector()
-    } else {
-        throw IllegalStateException("Your application context doesn't implement HasVectorInjector")
-    }
+fun Context.singletonEntryPoint(): SingletonEntryPoint {
+    return EntryPoints.get(applicationContext, SingletonEntryPoint::class.java)
 }
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt
index f066fd6784..90b08ef92b 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt
@@ -34,7 +34,7 @@ fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) {
         startSyncing(context)
     }
     refreshPushers()
-    context.vectorComponent().webRtcCallManager().checkForProtocolsSupportIfNeeded()
+    context.singletonEntryPoint().webRtcCallManager().checkForProtocolsSupportIfNeeded()
 }
 
 fun Session.startSyncing(context: Context) {
diff --git a/vector/src/main/java/im/vector/app/core/flow/TimingOperators.kt b/vector/src/main/java/im/vector/app/core/flow/TimingOperators.kt
new file mode 100644
index 0000000000..621a80d96e
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/flow/TimingOperators.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.flow
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ClosedReceiveChannelException
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.produce
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.consumeAsFlow
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.selects.select
+
+@ExperimentalCoroutinesApi
+fun <T> Flow<T>.chunk(durationInMillis: Long): Flow<List<T>> {
+    require(durationInMillis > 0) { "Duration should be greater than 0" }
+    return flow {
+        coroutineScope {
+            val events = ArrayList<T>()
+            val ticker = fixedPeriodTicker(durationInMillis)
+            try {
+                val upstreamValues = produce(capacity = Channel.CONFLATED) {
+                    collect { value -> send(value) }
+                }
+                while (isActive) {
+                    var hasTimedOut = false
+                    select<Unit> {
+                        upstreamValues.onReceive {
+                            events.add(it)
+                        }
+                        ticker.onReceive {
+                            hasTimedOut = true
+                        }
+                    }
+                    if (hasTimedOut && events.isNotEmpty()) {
+                        emit(events.toList())
+                        events.clear()
+                    }
+                }
+            } catch (e: ClosedReceiveChannelException) {
+                // drain remaining events
+                if (events.isNotEmpty()) emit(events.toList())
+            } finally {
+                ticker.cancel()
+            }
+        }
+    }
+}
+
+@ExperimentalCoroutinesApi
+fun <T> Flow<T>.throttleFirst(windowDuration: Long): Flow<T> = flow {
+    var windowStartTime = System.currentTimeMillis()
+    var emitted = false
+    collect { value ->
+        val currentTime = System.currentTimeMillis()
+        val delta = currentTime - windowStartTime
+        if (delta >= windowDuration) {
+            windowStartTime += delta / windowDuration * windowDuration
+            emitted = false
+        }
+        if (!emitted) {
+            emit(value)
+            emitted = true
+        }
+    }
+}
+
+fun tickerFlow(scope: CoroutineScope, delayMillis: Long, initialDelayMillis: Long = delayMillis): Flow<Unit> {
+    return scope.fixedPeriodTicker(delayMillis, initialDelayMillis).consumeAsFlow()
+}
+
+private fun CoroutineScope.fixedPeriodTicker(delayMillis: Long, initialDelayMillis: Long = delayMillis): ReceiveChannel<Unit> {
+    require(delayMillis >= 0) { "Expected non-negative delay, but has $delayMillis ms" }
+    require(initialDelayMillis >= 0) { "Expected non-negative initial delay, but has $initialDelayMillis ms" }
+    return produce(capacity = 0) {
+        delay(initialDelayMillis)
+        while (true) {
+            channel.send(Unit)
+            delay(delayMillis)
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/glide/AvatarPlaceholder.kt b/vector/src/main/java/im/vector/app/core/glide/AvatarPlaceholder.kt
index 9675e30042..e61f81de55 100644
--- a/vector/src/main/java/im/vector/app/core/glide/AvatarPlaceholder.kt
+++ b/vector/src/main/java/im/vector/app/core/glide/AvatarPlaceholder.kt
@@ -26,7 +26,7 @@ import com.bumptech.glide.load.model.ModelLoader
 import com.bumptech.glide.load.model.ModelLoaderFactory
 import com.bumptech.glide.load.model.MultiModelLoaderFactory
 import com.bumptech.glide.signature.ObjectKey
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.extensions.singletonEntryPoint
 import org.matrix.android.sdk.api.util.MatrixItem
 
 data class AvatarPlaceholder(val matrixItem: MatrixItem)
@@ -57,7 +57,7 @@ class AvatarPlaceholderModelLoader(private val context: Context) :
 class AvatarPlaceholderDataFetcher(context: Context, private val data: AvatarPlaceholder) :
     DataFetcher<Drawable> {
 
-    private val avatarRenderer = context.vectorComponent().avatarRenderer()
+    private val avatarRenderer = context.singletonEntryPoint().avatarRenderer()
 
     override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in Drawable>) {
         val avatarPlaceholder = avatarRenderer.getPlaceholderDrawable(data.matrixItem)
diff --git a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
index 7dfee7d981..6b42e3fff8 100644
--- a/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
+++ b/vector/src/main/java/im/vector/app/core/glide/VectorGlideModelLoader.kt
@@ -25,7 +25,7 @@ import com.bumptech.glide.load.model.ModelLoader
 import com.bumptech.glide.load.model.ModelLoaderFactory
 import com.bumptech.glide.load.model.MultiModelLoaderFactory
 import com.bumptech.glide.signature.ObjectKey
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.core.files.LocalFilesHelper
 import im.vector.app.features.media.ImageContentRenderer
 import im.vector.app.features.session.coroutineScope
@@ -67,7 +67,7 @@ class VectorGlideDataFetcher(context: Context,
     DataFetcher<InputStream> {
 
     private val localFilesHelper = LocalFilesHelper(context)
-    private val activeSessionHolder = context.vectorComponent().activeSessionHolder()
+    private val activeSessionHolder = context.singletonEntryPoint().activeSessionHolder()
 
     private val client = activeSessionHolder.getSafeActiveSession()?.getOkHttpClient() ?: OkHttpClient()
 
diff --git a/vector/src/main/java/im/vector/app/core/intent/Filename.kt b/vector/src/main/java/im/vector/app/core/intent/Filename.kt
index 5d118c19a1..a38602e4a5 100644
--- a/vector/src/main/java/im/vector/app/core/intent/Filename.kt
+++ b/vector/src/main/java/im/vector/app/core/intent/Filename.kt
@@ -19,15 +19,17 @@ package im.vector.app.core.intent
 import android.content.Context
 import android.net.Uri
 import android.provider.OpenableColumns
+import im.vector.lib.multipicker.utils.getColumnIndexOrNull
 
 fun getFilenameFromUri(context: Context?, uri: Uri): String? {
     if (context != null && uri.scheme == "content") {
-        val cursor = context.contentResolver.query(uri, null, null, null, null)
-        cursor?.use {
-            if (it.moveToFirst()) {
-                return it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
-            }
-        }
+        context.contentResolver.query(uri, null, null, null, null)
+                ?.use { cursor ->
+                    if (cursor.moveToFirst()) {
+                        return cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME)
+                                ?.let { cursor.getString(it) }
+                    }
+                }
     }
     return uri.path?.substringAfterLast('/')
 }
diff --git a/vector/src/main/java/im/vector/app/core/platform/LifecycleAwareLazy.kt b/vector/src/main/java/im/vector/app/core/platform/LifecycleAwareLazy.kt
index 283106232e..54add00459 100644
--- a/vector/src/main/java/im/vector/app/core/platform/LifecycleAwareLazy.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/LifecycleAwareLazy.kt
@@ -18,58 +18,56 @@ package im.vector.app.core.platform
 
 import androidx.annotation.MainThread
 import androidx.fragment.app.Fragment
+import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
 import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.OnLifecycleEvent
 
 fun <T> LifecycleOwner.lifecycleAwareLazy(initializer: () -> T): Lazy<T> = LifecycleAwareLazy(this, initializer)
 
 private object UninitializedValue
 
 class LifecycleAwareLazy<out T>(
-  private val owner: LifecycleOwner,
-  initializer: () -> T
-) : Lazy<T>, LifecycleObserver {
+        private val owner: LifecycleOwner,
+        initializer: () -> T
+) : Lazy<T>, DefaultLifecycleObserver {
 
-  private var initializer: (() -> T)? = initializer
+    private var initializer: (() -> T)? = initializer
 
-  private var _value: Any? = UninitializedValue
+    private var _value: Any? = UninitializedValue
 
-  @Suppress("UNCHECKED_CAST")
-  override val value: T
-    @MainThread
-    get() {
-      if (_value === UninitializedValue) {
-        _value = initializer!!()
-        attachToLifecycle()
-      }
-      return _value as T
+    @Suppress("UNCHECKED_CAST")
+    override val value: T
+        @MainThread
+        get() {
+            if (_value === UninitializedValue) {
+                _value = initializer!!()
+                attachToLifecycle()
+            }
+            return _value as T
+        }
+
+    override fun onDestroy(owner: LifecycleOwner) {
+        _value = UninitializedValue
+        detachFromLifecycle()
     }
 
-  @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-  fun resetValue() {
-    _value = UninitializedValue
-    detachFromLifecycle()
-  }
-
-  private fun attachToLifecycle() {
-    if (getLifecycleOwner().lifecycle.currentState == Lifecycle.State.DESTROYED) {
-      throw IllegalStateException("Initialization failed because lifecycle has been destroyed!")
+    private fun attachToLifecycle() {
+        if (getLifecycleOwner().lifecycle.currentState == Lifecycle.State.DESTROYED) {
+            throw IllegalStateException("Initialization failed because lifecycle has been destroyed!")
+        }
+        getLifecycleOwner().lifecycle.addObserver(this)
     }
-    getLifecycleOwner().lifecycle.addObserver(this)
-  }
 
-  private fun detachFromLifecycle() {
-    getLifecycleOwner().lifecycle.removeObserver(this)
-  }
+    private fun detachFromLifecycle() {
+        getLifecycleOwner().lifecycle.removeObserver(this)
+    }
 
-  private fun getLifecycleOwner() = when (owner) {
-    is Fragment -> owner.viewLifecycleOwner
-    else        -> owner
-  }
+    private fun getLifecycleOwner() = when (owner) {
+        is Fragment -> owner.viewLifecycleOwner
+        else        -> owner
+    }
 
-  override fun isInitialized(): Boolean = _value !== UninitializedValue
+    override fun isInitialized(): Boolean = _value !== UninitializedValue
 
-  override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
+    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
 }
diff --git a/vector/src/main/java/im/vector/app/core/platform/PendingIntentCompat.kt b/vector/src/main/java/im/vector/app/core/platform/PendingIntentCompat.kt
new file mode 100644
index 0000000000..832c11888c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/platform/PendingIntentCompat.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.platform
+
+import android.app.PendingIntent
+import android.os.Build
+
+object PendingIntentCompat {
+    val FLAG_IMMUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        PendingIntent.FLAG_IMMUTABLE
+    } else {
+        0
+    }
+
+    val FLAG_MUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+        PendingIntent.FLAG_MUTABLE
+    } else {
+        0
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt
index 7573bf2e8e..a70b2d66e6 100644
--- a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt
@@ -15,13 +15,10 @@
  */
 package im.vector.app.core.platform
 
-import androidx.annotation.CallSuper
 import androidx.core.view.isGone
 import androidx.core.view.isVisible
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.databinding.ActivityBinding
-import org.matrix.android.sdk.api.session.Session
 
 /**
  * Simple activity with a toolbar, a waiting overlay, and a fragment container and a session.
@@ -32,13 +29,6 @@ abstract class SimpleFragmentActivity : VectorBaseActivity<ActivityBinding>() {
 
     final override fun getCoordinatorLayout() = views.coordinatorLayout
 
-    lateinit var session: Session
-
-    @CallSuper
-    override fun injectWith(injector: ScreenComponent) {
-        session = injector.activeSessionHolder().getActiveSession()
-    }
-
     override fun initUiAndData() {
         configureToolbar(views.toolbar)
         waitingView = views.waitingView.waitingView
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
index fbfba10d21..0fd660effb 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.core.platform
 
+import android.annotation.SuppressLint
 import android.app.Activity
 import android.content.Context
 import android.content.res.Configuration
@@ -39,20 +40,17 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentFactory
 import androidx.fragment.app.FragmentManager
 import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
 import androidx.viewbinding.ViewBinding
 import com.airbnb.mvrx.MavericksView
 import com.bumptech.glide.util.Util
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.snackbar.Snackbar
-import com.jakewharton.rxbinding3.view.clicks
+import dagger.hilt.android.EntryPointAccessors
 import im.vector.app.BuildConfig
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.DaggerScreenComponent
-import im.vector.app.core.di.HasScreenInjector
-import im.vector.app.core.di.HasVectorInjector
-import im.vector.app.core.di.ScreenComponent
-import im.vector.app.core.di.VectorComponent
+import im.vector.app.core.di.ActivityEntryPoint
 import im.vector.app.core.dialogs.DialogLocker
 import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
 import im.vector.app.core.extensions.exhaustive
@@ -61,7 +59,8 @@ import im.vector.app.core.extensions.observeNotNull
 import im.vector.app.core.extensions.registerStartForActivityResult
 import im.vector.app.core.extensions.restart
 import im.vector.app.core.extensions.setTextOrHide
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.extensions.singletonEntryPoint
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.utils.toast
 import im.vector.app.features.MainActivity
 import im.vector.app.features.MainActivityArgs
@@ -80,16 +79,15 @@ import im.vector.app.features.settings.VectorPreferences
 import im.vector.app.features.themes.ActivityOtherThemes
 import im.vector.app.features.themes.ThemeUtils
 import im.vector.app.receivers.DebugReceiver
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.CompositeDisposable
-import io.reactivex.disposables.Disposable
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.failure.GlobalError
+import reactivecircus.flowbinding.android.view.clicks
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
-import kotlin.system.measureTimeMillis
+import javax.inject.Inject
 
-abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasScreenInjector, MavericksView {
+abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), MavericksView {
     /* ==========================================================================================
      * View
      * ========================================================================================== */
@@ -107,13 +105,12 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
 
     protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
         viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .stream()
+                .onEach {
                     hideWaitingView()
                     observer(it)
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
     }
 
     /* ==========================================================================================
@@ -122,10 +119,9 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
 
     protected fun View.debouncedClicks(onClicked: () -> Unit) {
         clicks()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe { onClicked() }
-                .disposeOnDestroy()
+                .throttleFirst(300)
+                .onEach { onClicked() }
+                .launchIn(lifecycleScope)
     }
 
     /* ==========================================================================================
@@ -136,8 +132,9 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
     private lateinit var sessionListener: SessionListener
     protected lateinit var bugReporter: BugReporter
     private lateinit var pinLocker: PinLocker
-    lateinit var rageShake: RageShake
 
+    @Inject
+    lateinit var rageShake: RageShake
     lateinit var navigator: Navigator
         private set
     private lateinit var fragmentFactory: FragmentFactory
@@ -153,11 +150,8 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
     // For debug only
     private var debugReceiver: DebugReceiver? = null
 
-    private val uiDisposables = CompositeDisposable()
     private val restorables = ArrayList<Restorable>()
 
-    private lateinit var screenComponent: ScreenComponent
-
     override fun attachBaseContext(base: Context) {
         val vectorConfiguration = VectorConfiguration(this)
         super.attachBaseContext(vectorConfiguration.getLocalisedContext(base))
@@ -180,32 +174,22 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
         return this
     }
 
-    protected fun Disposable.disposeOnDestroy() {
-        uiDisposables.add(this)
-    }
-
     @CallSuper
     override fun onCreate(savedInstanceState: Bundle?) {
         Timber.i("onCreate Activity ${javaClass.simpleName}")
-        val vectorComponent = getVectorComponent()
-        screenComponent = DaggerScreenComponent.factory().create(vectorComponent, this)
-        val timeForInjection = measureTimeMillis {
-            injectWith(screenComponent)
-        }
-        Timber.v("Injecting dependencies into ${javaClass.simpleName} took $timeForInjection ms")
+        val singletonEntryPoint = singletonEntryPoint()
+        val activityEntryPoint = EntryPointAccessors.fromActivity(this, ActivityEntryPoint::class.java)
         ThemeUtils.setActivityTheme(this, getOtherThemes())
-        fragmentFactory = screenComponent.fragmentFactory()
+        fragmentFactory = activityEntryPoint.fragmentFactory()
         supportFragmentManager.fragmentFactory = fragmentFactory
+        viewModelFactory = activityEntryPoint.viewModelFactory()
         super.onCreate(savedInstanceState)
-        viewModelFactory = screenComponent.viewModelFactory()
         configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
-        bugReporter = screenComponent.bugReporter()
-        pinLocker = screenComponent.pinLocker()
-        // Shake detector
-        rageShake = screenComponent.rageShake()
-        navigator = screenComponent.navigator()
-        activeSessionHolder = screenComponent.activeSessionHolder()
-        vectorPreferences = vectorComponent.vectorPreferences()
+        bugReporter = singletonEntryPoint.bugReporter()
+        pinLocker = singletonEntryPoint.pinLocker()
+        navigator = singletonEntryPoint.navigator()
+        activeSessionHolder = singletonEntryPoint.activeSessionHolder()
+        vectorPreferences = singletonEntryPoint.vectorPreferences()
         configurationViewModel.activityRestarter.observe(this) {
             if (!it.hasBeenHandled) {
                 // Recreate the Activity because configuration has changed
@@ -217,7 +201,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
                 navigator.openPinCode(this, pinStartForActivityResult, PinMode.AUTH)
             }
         }
-        sessionListener = vectorComponent.sessionListener()
+        sessionListener = singletonEntryPoint.sessionListener()
         sessionListener.globalErrorLiveData.observeEvent(this) {
             handleGlobalError(it)
         }
@@ -273,7 +257,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
     }
 
     private fun handleCertificateError(certificateError: GlobalError.CertificateError) {
-        vectorComponent()
+        singletonEntryPoint()
                 .unrecognizedCertificateDialog()
                 .show(this,
                         certificateError.fingerprint,
@@ -313,8 +297,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
     override fun onDestroy() {
         super.onDestroy()
         Timber.i("onDestroy Activity ${javaClass.simpleName}")
-
-        uiDisposables.dispose()
     }
 
     private val pinStartForActivityResult = registerStartForActivityResult { activityResult ->
@@ -403,12 +385,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
         bugReporter.inMultiWindowMode = isInMultiWindowMode
     }
 
-    override fun injector(): ScreenComponent {
-        return screenComponent
-    }
-
-    protected open fun injectWith(injector: ScreenComponent) = Unit
-
     protected fun createFragment(fragmentClass: Class<out Fragment>, args: Bundle?): Fragment {
         return fragmentFactory.instantiate(classLoader, fragmentClass.name).apply {
             arguments = args
@@ -419,10 +395,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
      * PRIVATE METHODS
      * ========================================================================================== */
 
-    internal fun getVectorComponent(): VectorComponent {
-        return (application as HasVectorInjector).injector()
-    }
-
     /**
      * Force to render the activity in fullscreen
      */
@@ -432,7 +404,12 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), HasSc
             // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
             window.setDecorFitsSystemWindows(false)
             // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
-            window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+            } else {
+                @SuppressLint("WrongConstant")
+                window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
+            }
             // New API instead of FLAG_TRANSLUCENT_STATUS
             window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar)
             // New API instead of FLAG_TRANSLUCENT_NAVIGATION
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt
index 68765d615e..20697c6d11 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt
@@ -26,29 +26,27 @@ import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.annotation.CallSuper
 import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
 import androidx.viewbinding.ViewBinding
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.MavericksView
 import com.google.android.material.bottomsheet.BottomSheetBehavior
 import com.google.android.material.bottomsheet.BottomSheetDialog
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment
-import com.jakewharton.rxbinding3.view.clicks
-import im.vector.app.core.di.DaggerScreenComponent
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.EntryPointAccessors
+import im.vector.app.core.di.ActivityEntryPoint
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.utils.DimensionConverter
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.CompositeDisposable
-import io.reactivex.disposables.Disposable
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.view.clicks
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
 
 /**
  * Add Mavericks capabilities, handle DI and bindings.
  */
 abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomSheetDialogFragment(), MavericksView {
 
-    private lateinit var screenComponent: ScreenComponent
-
     /* ==========================================================================================
      * View
      * ========================================================================================== */
@@ -110,26 +108,21 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
 
     @CallSuper
     override fun onDestroyView() {
-        uiDisposables.clear()
         _binding = null
         super.onDestroyView()
     }
 
     @CallSuper
     override fun onDestroy() {
-        uiDisposables.dispose()
         super.onDestroy()
     }
 
     override fun onAttach(context: Context) {
-        screenComponent = DaggerScreenComponent.factory().create(vectorBaseActivity.getVectorComponent(), vectorBaseActivity)
-        viewModelFactory = screenComponent.viewModelFactory()
+        val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
+        viewModelFactory = activityEntryPoint.viewModelFactory()
         super.onAttach(context)
-        injectWith(screenComponent)
     }
 
-    protected open fun injectWith(injector: ScreenComponent) = Unit
-
     override fun onResume() {
         super.onResume()
         Timber.i("onResume BottomSheet ${javaClass.simpleName}")
@@ -169,27 +162,15 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
         arguments = args?.let { Bundle().apply { putParcelable(Mavericks.KEY_ARG, it) } }
     }
 
-    /* ==========================================================================================
-     * Disposable
-     * ========================================================================================== */
-
-    private val uiDisposables = CompositeDisposable()
-
-    protected fun Disposable.disposeOnDestroyView(): Disposable {
-        uiDisposables.add(this)
-        return this
-    }
-
     /* ==========================================================================================
      * Views
      * ========================================================================================== */
 
     protected fun View.debouncedClicks(onClicked: () -> Unit) {
         clicks()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe { onClicked() }
-                .disposeOnDestroyView()
+                .throttleFirst(300)
+                .onEach { onClicked() }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     /* ==========================================================================================
@@ -198,11 +179,10 @@ abstract class VectorBaseBottomSheetDialogFragment<VB : ViewBinding> : BottomShe
 
     protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
         viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .stream()
+                .onEach {
                     observer(it)
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt
index 64b55291fb..f4e1fe84e1 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt
@@ -29,28 +29,28 @@ import androidx.annotation.MainThread
 import androidx.appcompat.app.AlertDialog
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
 import androidx.viewbinding.ViewBinding
 import com.airbnb.mvrx.MavericksView
 import com.bumptech.glide.util.Util.assertMainThread
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.jakewharton.rxbinding3.view.clicks
+import dagger.hilt.android.EntryPointAccessors
 import im.vector.app.R
-import im.vector.app.core.di.DaggerScreenComponent
-import im.vector.app.core.di.HasScreenInjector
-import im.vector.app.core.di.ScreenComponent
+import im.vector.app.core.di.ActivityEntryPoint
 import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
 import im.vector.app.core.error.ErrorFormatter
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.core.extensions.toMvRxBundle
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.features.navigation.Navigator
 import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.CompositeDisposable
-import io.reactivex.disposables.Disposable
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.view.clicks
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
 
-abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView, HasScreenInjector {
+abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView {
 
     protected val vectorBaseActivity: VectorBaseActivity<*> by lazy {
         activity as VectorBaseActivity<*>
@@ -60,8 +60,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView,
      * Navigator and other common objects
      * ========================================================================================== */
 
-    private lateinit var screenComponent: ScreenComponent
-
     protected lateinit var navigator: Navigator
     protected lateinit var errorFormatter: ErrorFormatter
     protected lateinit var unrecognizedCertificateDialog: UnrecognizedCertificateDialog
@@ -95,12 +93,13 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView,
      * ========================================================================================== */
 
     override fun onAttach(context: Context) {
-        screenComponent = DaggerScreenComponent.factory().create(vectorBaseActivity.getVectorComponent(), vectorBaseActivity)
-        navigator = screenComponent.navigator()
-        errorFormatter = screenComponent.errorFormatter()
-        unrecognizedCertificateDialog = screenComponent.unrecognizedCertificateDialog()
-        viewModelFactory = screenComponent.viewModelFactory()
-        childFragmentManager.fragmentFactory = screenComponent.fragmentFactory()
+        val singletonEntryPoint = context.singletonEntryPoint()
+        val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java)
+        navigator = singletonEntryPoint.navigator()
+        errorFormatter = singletonEntryPoint.errorFormatter()
+        unrecognizedCertificateDialog = singletonEntryPoint.unrecognizedCertificateDialog()
+        viewModelFactory = activityEntryPoint.viewModelFactory()
+        childFragmentManager.fragmentFactory = activityEntryPoint.fragmentFactory()
         super.onAttach(context)
     }
 
@@ -149,7 +148,6 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView,
     @CallSuper
     override fun onDestroyView() {
         Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
-        uiDisposables.clear()
         _binding = null
         super.onDestroyView()
     }
@@ -157,14 +155,9 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView,
     @CallSuper
     override fun onDestroy() {
         Timber.i("onDestroy Fragment ${javaClass.simpleName}")
-        uiDisposables.dispose()
         super.onDestroy()
     }
 
-    override fun injector(): ScreenComponent {
-        return screenComponent
-    }
-
     /* ==========================================================================================
      * Restorable
      * ========================================================================================== */
@@ -226,29 +219,18 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView,
         }
     }
 
-    /* ==========================================================================================
-     * Disposable
-     * ========================================================================================== */
-
-    private val uiDisposables = CompositeDisposable()
-
-    protected fun Disposable.disposeOnDestroyView() {
-        uiDisposables.add(this)
-    }
-
     /* ==========================================================================================
      * ViewEvents
      * ========================================================================================== */
 
     protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
         viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .stream()
+                .onEach {
                     dismissLoadingDialog()
                     observer(it)
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     /* ==========================================================================================
@@ -257,10 +239,9 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView,
 
     protected fun View.debouncedClicks(onClicked: () -> Unit) {
         clicks()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe { onClicked() }
-                .disposeOnDestroyView()
+                .throttleFirst(300)
+                .onEach { onClicked() }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     /* ==========================================================================================
diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt b/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt
index 6e7c24d4e9..c9d58f9545 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt
@@ -16,53 +16,17 @@
 
 package im.vector.app.core.platform
 
-import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.BaseMvRxViewModel
-import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
-import com.airbnb.mvrx.Success
+import com.airbnb.mvrx.MavericksViewModel
 import im.vector.app.core.utils.DataSource
 import im.vector.app.core.utils.PublishDataSource
-import io.reactivex.Observable
-import io.reactivex.Single
 
 abstract class VectorViewModel<S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents>(initialState: S) :
-        BaseMvRxViewModel<S>(initialState) {
-
-    interface Factory<S : MavericksState> {
-        fun create(state: S): BaseMvRxViewModel<S>
-    }
+        MavericksViewModel<S>(initialState) {
 
     // Used to post transient events to the View
     protected val _viewEvents = PublishDataSource<VE>()
     val viewEvents: DataSource<VE> = _viewEvents
 
-    /**
-     * This method does the same thing as the execute function, but it doesn't subscribe to the stream
-     * so you can use this in a switchMap or a flatMap
-     */
-    // False positive
-    @Suppress("USELESS_CAST", "NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER")
-    fun <T> Single<T>.toAsync(stateReducer: S.(Async<T>) -> S): Single<Async<T>> {
-        setState { stateReducer(Loading()) }
-        return map { Success(it) as Async<T> }
-                .onErrorReturn { Fail(it) }
-                .doOnSuccess { setState { stateReducer(it) } }
-    }
-
-    /**
-     * This method does the same thing as the execute function, but it doesn't subscribe to the stream
-     * so you can use this in a switchMap or a flatMap
-     */
-    // False positive
-    @Suppress("USELESS_CAST", "NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER")
-    fun <T> Observable<T>.toAsync(stateReducer: S.(Async<T>) -> S): Observable<Async<T>> {
-        setState { stateReducer(Loading()) }
-        return map { Success(it) as Async<T> }
-                .onErrorReturn { Fail(it) }
-                .doOnNext { setState { stateReducer(it) } }
-    }
-
     abstract fun handle(action: VA)
 }
diff --git a/vector/src/main/java/im/vector/app/core/preference/UserAvatarPreference.kt b/vector/src/main/java/im/vector/app/core/preference/UserAvatarPreference.kt
index 3bb50c6284..3095f98ea5 100755
--- a/vector/src/main/java/im/vector/app/core/preference/UserAvatarPreference.kt
+++ b/vector/src/main/java/im/vector/app/core/preference/UserAvatarPreference.kt
@@ -23,7 +23,7 @@ import android.widget.ProgressBar
 import androidx.preference.Preference
 import androidx.preference.PreferenceViewHolder
 import im.vector.app.R
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.features.home.AvatarRenderer
 import org.matrix.android.sdk.api.session.user.model.User
 import org.matrix.android.sdk.api.util.MatrixItem
@@ -33,7 +33,7 @@ class UserAvatarPreference : Preference {
     private var mAvatarView: ImageView? = null
     private var mLoadingProgressBar: ProgressBar? = null
 
-    private var avatarRenderer: AvatarRenderer = context.vectorComponent().avatarRenderer()
+    private var avatarRenderer: AvatarRenderer = context.singletonEntryPoint().avatarRenderer()
 
     private var userItem: MatrixItem.UserItem? = null
 
diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt
index add9032643..a6f8c99998 100755
--- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt
+++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt
@@ -31,9 +31,9 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 import com.squareup.moshi.Moshi
 import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.BuildConfig
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.extensions.vectorComponent
 import im.vector.app.core.network.WifiDetector
 import im.vector.app.features.badge.BadgeProxy
 import im.vector.app.features.notifications.NotifiableEventResolver
@@ -52,6 +52,7 @@ import org.matrix.android.sdk.api.session.Session
 import org.unifiedpush.android.connector.MessagingReceiver
 import org.unifiedpush.android.connector.MessagingReceiverHandler
 import timber.log.Timber
+import javax.inject.Inject
 
 @JsonClass(generateAdapter = true)
 data class UnifiedPushMessage(
@@ -73,18 +74,33 @@ data class Counts(
 
 private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
 
+/**
+ * Injected variables can't be into interfaces.
+ * We need to create an interface with a function
+ * to initialize these variables.
+ */
+interface VectorMessagingReceiverHandler : MessagingReceiverHandler {
+    fun init(notificationDrawerManager: NotificationDrawerManager,
+             notifiableEventResolver: NotifiableEventResolver,
+             pusherManager: PushersManager,
+             activeSessionHolder: ActiveSessionHolder,
+             vectorPreferences: VectorPreferences,
+             vectorDataStore: VectorDataStore,
+             wifiDetector: WifiDetector
+    )
+}
+
 /**
  * UnifiedPush handler.
  */
-val upHandler = object: MessagingReceiverHandler {
-
-    private lateinit var notificationDrawerManager: NotificationDrawerManager
-    private lateinit var notifiableEventResolver: NotifiableEventResolver
-    private lateinit var pusherManager: PushersManager
-    private lateinit var activeSessionHolder: ActiveSessionHolder
-    private lateinit var vectorPreferences: VectorPreferences
-    private lateinit var vectorDataStore: VectorDataStore
-    private lateinit var wifiDetector: WifiDetector
+val upHandler = object: VectorMessagingReceiverHandler {
+    lateinit var notificationDrawerManager: NotificationDrawerManager
+    lateinit var notifiableEventResolver: NotifiableEventResolver
+    lateinit var pusherManager: PushersManager
+    lateinit var activeSessionHolder: ActiveSessionHolder
+    lateinit var vectorPreferences: VectorPreferences
+    lateinit var vectorDataStore: VectorDataStore
+    lateinit var wifiDetector: WifiDetector
 
     private val coroutineScope = CoroutineScope(SupervisorJob())
 
@@ -93,16 +109,24 @@ val upHandler = object: MessagingReceiverHandler {
         Handler(Looper.getMainLooper())
     }
 
-    fun initVar(context: Context) {
-        with(context.vectorComponent()) {
-            notificationDrawerManager = notificationDrawerManager()
-            notifiableEventResolver = notifiableEventResolver()
-            pusherManager = pusherManager()
-            activeSessionHolder = activeSessionHolder()
-            vectorPreferences = vectorPreferences()
-            vectorDataStore = vectorDataStore()
-            wifiDetector = wifiDetector()
-        }
+    /**
+     * Called to init injected vars
+     */
+    override fun init(notificationDrawerManager: NotificationDrawerManager,
+                      notifiableEventResolver: NotifiableEventResolver,
+                      pusherManager: PushersManager,
+                      activeSessionHolder: ActiveSessionHolder,
+                      vectorPreferences: VectorPreferences,
+                      vectorDataStore: VectorDataStore,
+                      wifiDetector: WifiDetector) {
+        Timber.tag(loggerTag.value).d("Init vars")
+        this.notificationDrawerManager = notificationDrawerManager
+        this.notifiableEventResolver = notifiableEventResolver
+        this.pusherManager = pusherManager
+        this.activeSessionHolder = activeSessionHolder
+        this.vectorPreferences = vectorPreferences
+        this.vectorDataStore = vectorDataStore
+        this.wifiDetector = wifiDetector
     }
 
     /**
@@ -112,11 +136,10 @@ val upHandler = object: MessagingReceiverHandler {
      * @param instance connection, for multi-account
      */
     override fun onMessage(context: Context?, message: String, instance: String) {
-        initVar(context!!)
         if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
-            Timber.tag(loggerTag.value).d("## onMessageReceived() %s", message)
+            Timber.tag(loggerTag.value).d("## onMessage() %s", message)
         } else {
-            Timber.tag(loggerTag.value).d("## onMessageReceived()")
+            Timber.tag(loggerTag.value).d("## onMessage() received")
         }
 
         runBlocking {
@@ -128,7 +151,7 @@ val upHandler = object: MessagingReceiverHandler {
                 .build()
         lateinit var notification: Notification
 
-        if (UPHelper.isEmbeddedDistributor(context)) {
+        if (UPHelper.isEmbeddedDistributor(context!!)) {
             notification = moshi.adapter(Notification::class.java)
                     .fromJson(message) ?: return
         } else {
@@ -138,7 +161,6 @@ val upHandler = object: MessagingReceiverHandler {
             notification.unread = notification.counts.unread
         }
 
-
         // Diagnostic Push
         if (notification.eventId == PushersManager.TEST_EVENT_ID) {
             val intent = Intent(NotificationUtils.PUSH_ACTION)
@@ -168,10 +190,9 @@ val upHandler = object: MessagingReceiverHandler {
      * you retrieve the token.
      */
     override fun onNewEndpoint(context: Context?, endpoint: String, instance: String) {
-        initVar(context!!)
         Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
         if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
-            val gateway = UPHelper.customOrDefaultGateway(context, endpoint)
+            val gateway = UPHelper.customOrDefaultGateway(context!!, endpoint)
             if (UPHelper.getUpEndpoint(context) != endpoint
                     || UPHelper.getPushGateway(context) != gateway) {
                 UPHelper.storePushGateway(context, gateway)
@@ -181,7 +202,7 @@ val upHandler = object: MessagingReceiverHandler {
                 Timber.tag(loggerTag.value).i("onNewEndpoint: skipped")
             }
         }
-        if (!UPHelper.allowBackgroundSync(context)) {
+        if (context == null || !UPHelper.allowBackgroundSync(context)) {
             val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
             vectorPreferences.setFdroidSyncBackgroundMode(mode)
         }
@@ -197,12 +218,11 @@ val upHandler = object: MessagingReceiverHandler {
 
     override fun onUnregistered(context: Context?, instance: String) {
         Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
-        initVar(context!!)
         val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY
         vectorPreferences.setFdroidSyncBackgroundMode(mode)
         runBlocking {
             try {
-                pusherManager.unregisterPusher(context, UPHelper.getUpEndpoint(context)!!)
+                pusherManager.unregisterPusher(context!!, UPHelper.getUpEndpoint(context)!!)
             } catch (e: Exception) {
                 Timber.tag(loggerTag.value).d("Probably unregistering a non existant pusher")
             }
@@ -264,14 +284,12 @@ val upHandler = object: MessagingReceiverHandler {
             Timber.tag(loggerTag.value).d("Fast lane: start request")
             val event = tryOrNull { session.getEvent(roomId, eventId) } ?: return@launch
 
-            val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event)
+            val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event, canBeReplaced = true)
 
             resolvedEvent
                     ?.also { Timber.tag(loggerTag.value).d("Fast lane: notify drawer") }
                     ?.let {
-                        it.isPushGatewayEvent = true
-                        notificationDrawerManager.onNotifiableEventReceived(it)
-                        notificationDrawerManager.refreshNotificationDrawer()
+                        notificationDrawerManager.updateEvents { it.onNotifiableEventReceived(resolvedEvent) }
                     }
         }
     }
@@ -292,4 +310,32 @@ val upHandler = object: MessagingReceiverHandler {
     }
 }
 
-class VectorMessagingReceiver : MessagingReceiver(upHandler)
+/**
+ * Hilt injection happen at super.onReceive().
+ * We must implement an intermediate receiver to
+ * initialize vars of the handler before
+ * super.onReceive().
+ */
+open class InjectedMessagingReceiver : MessagingReceiver(upHandler) {
+    @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
+    @Inject lateinit var notifiableEventResolver: NotifiableEventResolver
+    @Inject lateinit var pusherManager: PushersManager
+    @Inject lateinit var activeSessionHolder: ActiveSessionHolder
+    @Inject lateinit var vectorPreferences: VectorPreferences
+    @Inject lateinit var vectorDataStore: VectorDataStore
+    @Inject lateinit var wifiDetector: WifiDetector
+
+    override fun onReceive(context: Context?, intent: Intent?) {
+        upHandler.init(notificationDrawerManager,
+                notifiableEventResolver,
+                pusherManager,
+                activeSessionHolder,
+                vectorPreferences,
+                vectorDataStore,
+                wifiDetector)
+        super.onReceive(context, intent) // Injection would happen here
+    }
+}
+
+@AndroidEntryPoint
+class VectorMessagingReceiver : InjectedMessagingReceiver()
diff --git a/vector/src/main/java/im/vector/app/core/receiver/AlarmSyncBroadcastReceiver.kt b/vector/src/main/java/im/vector/app/core/receiver/AlarmSyncBroadcastReceiver.kt
index 37a10cccda..c1135288aa 100644
--- a/vector/src/main/java/im/vector/app/core/receiver/AlarmSyncBroadcastReceiver.kt
+++ b/vector/src/main/java/im/vector/app/core/receiver/AlarmSyncBroadcastReceiver.kt
@@ -24,7 +24,8 @@ import android.content.Intent
 import android.os.Build
 import androidx.core.content.ContextCompat
 import androidx.core.content.getSystemService
-import im.vector.app.core.di.HasVectorInjector
+import im.vector.app.core.extensions.singletonEntryPoint
+import im.vector.app.core.platform.PendingIntentCompat
 import im.vector.app.core.services.VectorSyncService
 import org.matrix.android.sdk.internal.session.sync.job.SyncService
 import timber.log.Timber
@@ -33,9 +34,8 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
 
     override fun onReceive(context: Context, intent: Intent) {
         Timber.d("## Sync: AlarmSyncBroadcastReceiver received intent")
-        val vectorPreferences = (context.applicationContext as? HasVectorInjector)
-                ?.injector()
-                ?.takeIf { it.activeSessionHolder().getSafeActiveSession() != null }
+        val vectorPreferences = context.singletonEntryPoint()
+                .takeIf { it.activeSessionHolder().getSafeActiveSession() != null }
                 ?.vectorPreferences()
                 ?: return Unit.also { Timber.v("No active session, so don't launch sync service.") }
 
@@ -68,7 +68,12 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
                 putExtra(SyncService.EXTRA_SESSION_ID, sessionId)
                 putExtra(SyncService.EXTRA_PERIODIC, true)
             }
-            val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+            val pIntent = PendingIntent.getBroadcast(
+                    context,
+                    REQUEST_CODE,
+                    intent,
+                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+            )
             val firstMillis = System.currentTimeMillis() + delayInSeconds * 1000L
             val alarmMgr = context.getSystemService<AlarmManager>()!!
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -81,7 +86,12 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
         fun cancelAlarm(context: Context) {
             Timber.v("## Sync: Cancel alarm for background sync")
             val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
-            val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+            val pIntent = PendingIntent.getBroadcast(
+                    context,
+                    REQUEST_CODE,
+                    intent,
+                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+            )
             val alarmMgr = context.getSystemService<AlarmManager>()!!
             alarmMgr.cancel(pIntent)
 
diff --git a/vector/src/main/java/im/vector/app/core/receiver/BackgroundSyncStarter.kt b/vector/src/main/java/im/vector/app/core/receiver/BackgroundSyncStarter.kt
index b3789ef6df..19eb344ff5 100644
--- a/vector/src/main/java/im/vector/app/core/receiver/BackgroundSyncStarter.kt
+++ b/vector/src/main/java/im/vector/app/core/receiver/BackgroundSyncStarter.kt
@@ -26,9 +26,8 @@ object BackgroundSyncStarter {
     fun start(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) {
         if (vectorPreferences.areNotificationEnabledForDevice()) {
             val activeSession = activeSessionHolder.getSafeActiveSession() ?: return
-
             when (vectorPreferences.getFdroidSyncBackgroundMode()) {
-                BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY -> {
+                BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY  -> {
                     // we rely on periodic worker
                     Timber.i("## Sync: Work scheduled to periodically sync in ${vectorPreferences.backgroundSyncDelay()}s")
                     activeSession.startAutomaticBackgroundSync(
@@ -41,7 +40,7 @@ object BackgroundSyncStarter {
                     AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, vectorPreferences.backgroundSyncDelay())
                     Timber.i("## Sync: Alarm scheduled to start syncing")
                 }
-                BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED -> {
+                BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED     -> {
                     // we do nothing
                     Timber.i("## Sync: background sync is disabled")
                 }
diff --git a/vector/src/main/java/im/vector/app/core/receiver/OnApplicationUpgradeOrRebootReceiver.kt b/vector/src/main/java/im/vector/app/core/receiver/OnApplicationUpgradeOrRebootReceiver.kt
index b1989eaab7..6a4f71e5a9 100644
--- a/vector/src/main/java/im/vector/app/core/receiver/OnApplicationUpgradeOrRebootReceiver.kt
+++ b/vector/src/main/java/im/vector/app/core/receiver/OnApplicationUpgradeOrRebootReceiver.kt
@@ -20,21 +20,18 @@ package im.vector.app.core.receiver
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
-import im.vector.app.core.di.HasVectorInjector
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.extensions.singletonEntryPoint
 import timber.log.Timber
 
 class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
 
     override fun onReceive(context: Context, intent: Intent) {
         Timber.v("## onReceive() ${intent.action}")
-        val appContext = context.applicationContext
-        if (appContext is HasVectorInjector) {
+        val singletonEntryPoint = context.singletonEntryPoint()
             BackgroundSyncStarter.start(
                     context,
-                    appContext.vectorComponent().vectorPreferences(),
-                    appContext.injector().activeSessionHolder()
+                    singletonEntryPoint.vectorPreferences(),
+                    singletonEntryPoint.activeSessionHolder()
             )
-        }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/core/rx/RxConfig.kt b/vector/src/main/java/im/vector/app/core/rx/RxConfig.kt
deleted file mode 100644
index ab0ffb7802..0000000000
--- a/vector/src/main/java/im/vector/app/core/rx/RxConfig.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.core.rx
-
-import im.vector.app.features.settings.VectorPreferences
-import io.reactivex.plugins.RxJavaPlugins
-import timber.log.Timber
-import javax.inject.Inject
-
-class RxConfig @Inject constructor(
-        private val vectorPreferences: VectorPreferences
-) {
-
-    /**
-     * Make sure unhandled Rx error does not crash the app in production
-     */
-    fun setupRxPlugin() {
-        RxJavaPlugins.setErrorHandler { throwable ->
-            Timber.e(throwable, "RxError")
-            // is InterruptedException -> fine, some blocking code was interrupted by a dispose call
-            if (throwable !is InterruptedException) {
-                // Avoid crash in production, except if user wants it
-                if (vectorPreferences.failFast()) {
-                    throw throwable
-                }
-            }
-        }
-    }
-}
diff --git a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt
index faa921b99e..524ff37914 100644
--- a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt
+++ b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt
@@ -62,6 +62,10 @@ class CallRingPlayerIncoming(
         val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
         ringtone = RingtoneManager.getRingtone(applicationContext, ringtoneUri)
         Timber.v("Play ringtone for incoming call")
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            ringtone?.isLooping = true
+        }
         ringtone?.play()
     }
 
diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt
index 5e07bb76c6..d194434641 100644
--- a/vector/src/main/java/im/vector/app/core/services/CallService.kt
+++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt
@@ -26,7 +26,8 @@ import androidx.core.app.NotificationManagerCompat
 import androidx.core.content.ContextCompat
 import androidx.media.session.MediaButtonReceiver
 import com.airbnb.mvrx.Mavericks
-import im.vector.app.core.extensions.vectorComponent
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.features.call.CallArgs
 import im.vector.app.features.call.VectorCallActivity
 import im.vector.app.features.call.telecom.CallConnection
@@ -42,23 +43,25 @@ import org.matrix.android.sdk.api.logger.LoggerTag
 import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
 import org.matrix.android.sdk.api.util.MatrixItem
 import timber.log.Timber
+import javax.inject.Inject
 
 private val loggerTag = LoggerTag("CallService", LoggerTag.VOIP)
 
 /**
  * Foreground service to manage calls
  */
+@AndroidEntryPoint
 class CallService : VectorService() {
 
     private val connections = mutableMapOf<String, CallConnection>()
     private val knownCalls = mutableMapOf<String, CallInformation>()
     private val connectedCallIds = mutableSetOf<String>()
 
-    private lateinit var notificationManager: NotificationManagerCompat
-    private lateinit var notificationUtils: NotificationUtils
-    private lateinit var callManager: WebRtcCallManager
-    private lateinit var avatarRenderer: AvatarRenderer
-    private lateinit var alertManager: PopupAlertManager
+    lateinit var notificationManager: NotificationManagerCompat
+    @Inject lateinit var notificationUtils: NotificationUtils
+    @Inject lateinit var callManager: WebRtcCallManager
+    @Inject lateinit var avatarRenderer: AvatarRenderer
+    @Inject lateinit var alertManager: PopupAlertManager
 
     private var callRingPlayerIncoming: CallRingPlayerIncoming? = null
     private var callRingPlayerOutgoing: CallRingPlayerOutgoing? = null
@@ -80,10 +83,6 @@ class CallService : VectorService() {
     override fun onCreate() {
         super.onCreate()
         notificationManager = NotificationManagerCompat.from(this)
-        notificationUtils = vectorComponent().notificationUtils()
-        callManager = vectorComponent().webRtcCallManager()
-        avatarRenderer = vectorComponent().avatarRenderer()
-        alertManager = vectorComponent().alertManager()
         callRingPlayerIncoming = CallRingPlayerIncoming(applicationContext, notificationUtils)
         callRingPlayerOutgoing = CallRingPlayerOutgoing(applicationContext)
     }
@@ -298,7 +297,7 @@ class CallService : VectorService() {
                 callId = this.callId,
                 nativeRoomId = this.nativeRoomId,
                 opponentUserId = this.mxCall.opponentUserId,
-                opponentMatrixItem = vectorComponent().activeSessionHolder().getSafeActiveSession()?.let {
+                opponentMatrixItem = singletonEntryPoint().activeSessionHolder().getSafeActiveSession()?.let {
                     this.getOpponentAsMatrixItem(it)
                 },
                 isVideoCall = this.mxCall.isVideoCall,
diff --git a/vector/src/main/java/im/vector/app/core/di/HasVectorInjector.kt b/vector/src/main/java/im/vector/app/core/services/GuardServiceStarter.kt
similarity index 80%
rename from vector/src/main/java/im/vector/app/core/di/HasVectorInjector.kt
rename to vector/src/main/java/im/vector/app/core/services/GuardServiceStarter.kt
index 79254defcc..71c6816cea 100644
--- a/vector/src/main/java/im/vector/app/core/di/HasVectorInjector.kt
+++ b/vector/src/main/java/im/vector/app/core/services/GuardServiceStarter.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 New Vector Ltd
+ * Copyright (c) 2021 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package im.vector.app.core.di
+package im.vector.app.core.services
 
-interface HasVectorInjector {
-
-    fun injector(): VectorComponent
+interface GuardServiceStarter {
+    fun start() {}
+    fun stop() {}
 }
diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt
index 2a00e94976..a6f6d8d82f 100644
--- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt
+++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt
@@ -30,13 +30,16 @@ import androidx.work.WorkManager
 import androidx.work.WorkRequest
 import androidx.work.Worker
 import androidx.work.WorkerParameters
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.platform.PendingIntentCompat
 import im.vector.app.features.notifications.NotificationUtils
 import im.vector.app.features.settings.BackgroundSyncMode
 import org.matrix.android.sdk.internal.session.sync.job.SyncService
 import timber.log.Timber
+import javax.inject.Inject
 
+@AndroidEntryPoint
 class VectorSyncService : SyncService() {
 
     companion object {
@@ -71,12 +74,7 @@ class VectorSyncService : SyncService() {
         }
     }
 
-    private lateinit var notificationUtils: NotificationUtils
-
-    override fun onCreate() {
-        super.onCreate()
-        notificationUtils = vectorComponent().notificationUtils()
-    }
+    @Inject lateinit var notificationUtils: NotificationUtils
 
     override fun getDefaultSyncDelaySeconds() = BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS
 
@@ -86,7 +84,7 @@ class VectorSyncService : SyncService() {
         val notificationSubtitleRes = if (isInitialSync) {
             R.string.notification_initial_sync
         } else {
-            R.string.notification_listening_for_events
+            R.string.notification_listening_for_notifications
         }
         val notification = notificationUtils.buildForegroundServiceNotification(notificationSubtitleRes, false)
         startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification)
@@ -202,9 +200,9 @@ private fun Context.rescheduleSyncService(sessionId: String,
         startService(intent)
     } else {
         val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            PendingIntent.getForegroundService(this, 0, intent, 0)
+            PendingIntent.getForegroundService(this, 0, intent, PendingIntentCompat.FLAG_IMMUTABLE)
         } else {
-            PendingIntent.getService(this, 0, intent, 0)
+            PendingIntent.getService(this, 0, intent, PendingIntentCompat.FLAG_IMMUTABLE)
         }
         val firstMillis = System.currentTimeMillis() + syncDelaySeconds * 1000L
         val alarmMgr = getSystemService<AlarmManager>()!!
diff --git a/vector/src/main/java/im/vector/app/core/ui/list/GenericButtonItem.kt b/vector/src/main/java/im/vector/app/core/ui/list/GenericButtonItem.kt
index eb683631fd..fe59c82ce9 100644
--- a/vector/src/main/java/im/vector/app/core/ui/list/GenericButtonItem.kt
+++ b/vector/src/main/java/im/vector/app/core/ui/list/GenericButtonItem.kt
@@ -15,6 +15,8 @@
  */
 package im.vector.app.core.ui.list
 
+import android.graphics.Typeface
+import android.view.Gravity
 import androidx.annotation.ColorInt
 import androidx.annotation.DrawableRes
 import com.airbnb.epoxy.EpoxyAttribute
@@ -47,6 +49,12 @@ abstract class GenericButtonItem : VectorEpoxyModel<GenericButtonItem.Holder>()
     @DrawableRes
     var iconRes: Int? = null
 
+    @EpoxyAttribute
+    var gravity: Int = Gravity.CENTER
+
+    @EpoxyAttribute
+    var bold: Boolean = false
+
     override fun bind(holder: Holder) {
         super.bind(holder)
         holder.button.text = text
@@ -58,6 +66,10 @@ abstract class GenericButtonItem : VectorEpoxyModel<GenericButtonItem.Holder>()
             holder.button.icon = null
         }
 
+        holder.button.gravity = gravity or Gravity.CENTER_VERTICAL
+        val textStyle = if (bold) Typeface.BOLD else Typeface.NORMAL
+        holder.button.setTypeface(null, textStyle)
+
         holder.button.onClick(buttonClickAction)
     }
 
diff --git a/vector/src/main/java/im/vector/app/core/utils/CountUpTimer.kt b/vector/src/main/java/im/vector/app/core/utils/CountUpTimer.kt
index a029f4eec9..b58d0fb3f6 100644
--- a/vector/src/main/java/im/vector/app/core/utils/CountUpTimer.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/CountUpTimer.kt
@@ -16,23 +16,36 @@
 
 package im.vector.app.core.utils
 
-import io.reactivex.Observable
-import java.util.concurrent.TimeUnit
+import im.vector.app.core.flow.tickerFlow
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import java.util.concurrent.atomic.AtomicBoolean
 import java.util.concurrent.atomic.AtomicLong
 
 class CountUpTimer(private val intervalInMs: Long = 1_000) {
 
+    private val coroutineScope = CoroutineScope(Dispatchers.Main)
     private val elapsedTime: AtomicLong = AtomicLong()
     private val resumed: AtomicBoolean = AtomicBoolean(false)
 
-    private val disposable = Observable.interval(intervalInMs / 10, TimeUnit.MILLISECONDS)
-            .filter { resumed.get() }
-            .map { elapsedTime.addAndGet(intervalInMs / 10) }
-            .filter { it % intervalInMs == 0L }
-            .subscribe {
-                tickListener?.onTick(it)
-            }
+    init {
+        startCounter()
+    }
+
+    private fun startCounter() {
+        tickerFlow(coroutineScope, intervalInMs / 10)
+                .filter { resumed.get() }
+                .map { elapsedTime.addAndGet(intervalInMs / 10) }
+                .filter { it % intervalInMs == 0L }
+                .onEach {
+                    tickListener?.onTick(it)
+                }.launchIn(coroutineScope)
+    }
 
     var tickListener: TickListener? = null
 
@@ -49,7 +62,7 @@ class CountUpTimer(private val intervalInMs: Long = 1_000) {
     }
 
     fun stop() {
-        disposable.dispose()
+        coroutineScope.cancel()
     }
 
     interface TickListener {
diff --git a/vector/src/main/java/im/vector/app/core/utils/DataSource.kt b/vector/src/main/java/im/vector/app/core/utils/DataSource.kt
index fc4ee330bb..f83eda68e9 100644
--- a/vector/src/main/java/im/vector/app/core/utils/DataSource.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/DataSource.kt
@@ -16,13 +16,12 @@
 
 package im.vector.app.core.utils
 
-import com.jakewharton.rxrelay2.BehaviorRelay
-import com.jakewharton.rxrelay2.PublishRelay
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
 
 interface DataSource<T> {
-    fun observe(): Observable<T>
+    fun stream(): Flow<T>
 }
 
 interface MutableDataSource<T> : DataSource<T> {
@@ -34,25 +33,17 @@ interface MutableDataSource<T> : DataSource<T> {
  */
 open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableDataSource<T> {
 
-    private val behaviorRelay = createRelay()
+    private val mutableFlow = MutableSharedFlow<T>(replay = 1)
 
     val currentValue: T?
-        get() = behaviorRelay.value
+        get() = mutableFlow.replayCache.firstOrNull()
 
-    override fun observe(): Observable<T> {
-        return behaviorRelay.hide().observeOn(AndroidSchedulers.mainThread())
+    override fun stream(): Flow<T> {
+        return mutableFlow
     }
 
     override fun post(value: T) {
-        behaviorRelay.accept(value!!)
-    }
-
-    private fun createRelay(): BehaviorRelay<T> {
-        return if (defaultValue == null) {
-            BehaviorRelay.create()
-        } else {
-            BehaviorRelay.createDefault(defaultValue)
-        }
+        mutableFlow.tryEmit(value)
     }
 }
 
@@ -61,13 +52,13 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
  */
 open class PublishDataSource<T> : MutableDataSource<T> {
 
-    private val publishRelay = PublishRelay.create<T>()
+    private val mutableFlow = MutableSharedFlow<T>(replay = 0, extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
 
-    override fun observe(): Observable<T> {
-        return publishRelay.hide().observeOn(AndroidSchedulers.mainThread())
+    override fun stream(): Flow<T> {
+        return mutableFlow
     }
 
     override fun post(value: T) {
-        publishRelay.accept(value!!)
+        mutableFlow.tryEmit(value)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt b/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt
index ed3ae00567..ad62b0fcb1 100644
--- a/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt
@@ -42,8 +42,8 @@ fun Context.displayInWebView(url: String) {
 
 fun Context.showIdentityServerConsentDialog(configuredIdentityServer: String?, policyLinkCallback: () -> Unit, consentCallBack: (() -> Unit)) {
     MaterialAlertDialogBuilder(this)
-            .setTitle(R.string.identity_server_consent_dialog_title)
-            .setMessage(getString(R.string.identity_server_consent_dialog_content, configuredIdentityServer ?: ""))
+            .setTitle(getString(R.string.identity_server_consent_dialog_title_2, configuredIdentityServer ?: ""))
+            .setMessage(R.string.identity_server_consent_dialog_content_2)
             .setPositiveButton(R.string.yes) { _, _ ->
                 consentCallBack.invoke()
             }
diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt
index e124dbdf6e..8e0995b426 100644
--- a/vector/src/main/java/im/vector/app/features/MainActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt
@@ -24,9 +24,9 @@ import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import com.bumptech.glide.Glide
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.startSyncing
 import im.vector.app.core.platform.VectorBaseActivity
@@ -67,6 +67,7 @@ data class MainActivityArgs(
  * This Activity, when started with argument, is also doing some cleanup when user signs out,
  * clears cache, is logged out, or is soft logged out
  */
+@AndroidEntryPoint
 class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity {
 
     companion object {
@@ -98,10 +99,6 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
     @Inject lateinit var pinLocker: PinLocker
     @Inject lateinit var popupAlertManager: PopupAlertManager
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         args = parseArgs()
diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt
index 35644e1843..6c349d18dc 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt
@@ -75,6 +75,7 @@ class AttachmentTypeSelectorView(context: Context,
         views.attachmentStickersButton.configure(Type.STICKER)
         views.attachmentAudioButton.configure(Type.AUDIO)
         views.attachmentContactButton.configure(Type.CONTACT)
+        views.attachmentPollButton.configure(Type.POLL)
         width = LinearLayout.LayoutParams.MATCH_PARENT
         height = LinearLayout.LayoutParams.WRAP_CONTENT
         animationStyle = 0
@@ -108,6 +109,7 @@ class AttachmentTypeSelectorView(context: Context,
         animateButtonIn(views.attachmentAudioButton, 0)
         animateButtonIn(views.attachmentContactButton, ANIMATION_DURATION / 4)
         animateButtonIn(views.attachmentStickersButton, ANIMATION_DURATION / 2)
+        animateButtonIn(views.attachmentPollButton, ANIMATION_DURATION / 4)
     }
 
     override fun dismiss() {
@@ -212,6 +214,7 @@ class AttachmentTypeSelectorView(context: Context,
         FILE(PERMISSIONS_EMPTY),
         STICKER(PERMISSIONS_EMPTY),
         AUDIO(PERMISSIONS_EMPTY),
-        CONTACT(PERMISSIONS_FOR_PICKING_CONTACT)
+        CONTACT(PERMISSIONS_FOR_PICKING_CONTACT),
+        POLL(PERMISSIONS_EMPTY)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt
index 6c25f688bd..939dd9f11d 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt
@@ -20,6 +20,7 @@ package im.vector.app.features.attachments.preview
 import android.content.Context
 import android.content.Intent
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
@@ -28,6 +29,7 @@ import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.themes.ActivityOtherThemes
 import org.matrix.android.sdk.api.session.content.ContentAttachmentData
 
+@AndroidEntryPoint
 class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
 
     companion object {
diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt
index b7f570672b..e3c9795b13 100644
--- a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt
@@ -29,8 +29,8 @@ import androidx.browser.customtabs.CustomTabsSession
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.SimpleFragmentActivity
 import im.vector.app.core.utils.openUrlInChromeCustomTab
@@ -42,7 +42,8 @@ import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
 import timber.log.Timber
 import javax.inject.Inject
 
-class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
+@AndroidEntryPoint
+class ReAuthActivity : SimpleFragmentActivity() {
 
     @Parcelize
     data class Args(
@@ -59,14 +60,6 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
     private var customTabsSession: CustomTabsSession? = null
 
     @Inject lateinit var authenticationService: AuthenticationService
-    @Inject lateinit var reAuthViewModelFactory: ReAuthViewModel.Factory
-
-    override fun create(initialState: ReAuthState) = reAuthViewModelFactory.create(initialState)
-
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
 
     private val sharedViewModel: ReAuthViewModel by viewModel()
 
diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt
index 449270644e..830fd4e79d 100644
--- a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt
@@ -16,13 +16,12 @@
 
 package im.vector.app.features.auth
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
 import org.matrix.android.sdk.api.session.Session
@@ -35,20 +34,11 @@ class ReAuthViewModel @AssistedInject constructor(
 ) : VectorViewModel<ReAuthState, ReAuthActions, ReAuthEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ReAuthState): ReAuthViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ReAuthViewModel, ReAuthState> {
+        override fun create(initialState: ReAuthState): ReAuthViewModel
     }
 
-    companion object : MavericksViewModelFactory<ReAuthViewModel, ReAuthState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: ReAuthState): ReAuthViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<ReAuthViewModel, ReAuthState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: ReAuthActions) = withState { state ->
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt
index f9e2338077..e38b53c858 100644
--- a/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/call/CallControlsBottomSheet.kt
@@ -23,10 +23,12 @@ import android.view.ViewGroup
 import androidx.core.content.ContextCompat
 import androidx.core.view.isVisible
 import com.airbnb.mvrx.activityViewModel
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetCallControlsBinding
 
+@AndroidEntryPoint
 class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallControlsBinding>() {
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetCallControlsBinding {
         return BottomSheetCallControlsBinding.inflate(inflater, container, false)
@@ -37,7 +39,7 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetC
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        callViewModel.subscribe(this) {
+        callViewModel.onEach {
             renderState(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt
index 0654942d4b..2406cbc625 100644
--- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt
@@ -35,14 +35,15 @@ import androidx.core.content.ContextCompat
 import androidx.core.content.getSystemService
 import androidx.core.view.isInvisible
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.card.MaterialCardView
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
@@ -61,7 +62,8 @@ import im.vector.app.features.home.room.detail.RoomDetailActivity
 import im.vector.app.features.home.room.detail.RoomDetailArgs
 import io.github.hyuwah.draggableviewlib.DraggableView
 import io.github.hyuwah.draggableviewlib.setupDraggable
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.logger.LoggerTag
@@ -85,21 +87,16 @@ data class CallArgs(
 
 private val loggerTag = LoggerTag("VectorCallActivity", LoggerTag.VOIP)
 
+@AndroidEntryPoint
 class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallControlsView.InteractionListener {
 
     override fun getBinding() = ActivityCallBinding.inflate(layoutInflater)
 
+    @Inject lateinit var callManager: WebRtcCallManager
     @Inject lateinit var avatarRenderer: AvatarRenderer
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     private val callViewModel: VectorCallViewModel by viewModel()
 
-    @Inject lateinit var callManager: WebRtcCallManager
-    @Inject lateinit var viewModelFactory: VectorCallViewModel.Factory
-
     private val dialPadCallback = object : DialPadFragment.Callback {
         override fun onDigitAppended(digit: String) {
             callViewModel.handle(VectorCallViewActions.SendDtmfDigit(digit))
@@ -135,7 +132,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
         setSupportActionBar(views.callToolbar)
         configureCallViews()
 
-        callViewModel.subscribe(this) {
+        callViewModel.onEach {
             renderState(it)
         }
 
@@ -146,12 +143,11 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
         }
 
         callViewModel.viewEvents
-                .observe()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .stream()
+                .onEach {
                     handleViewEvents(it)
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
 
         callViewModel.onEach(VectorCallViewState::callId, VectorCallViewState::isVideoCall) { _, isVideoCall ->
             if (isVideoCall) {
diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
index d8aaca9bd8..5af2b826af 100644
--- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
@@ -21,10 +21,11 @@ import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.call.audio.CallAudioManager
@@ -341,16 +342,9 @@ class VectorCallViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: VectorCallViewState): VectorCallViewModel
+    interface Factory : MavericksAssistedViewModelFactory<VectorCallViewModel, VectorCallViewState> {
+        override fun create(initialState: VectorCallViewState): VectorCallViewModel
     }
 
-    companion object : MavericksViewModelFactory<VectorCallViewModel, VectorCallViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: VectorCallViewState): VectorCallViewModel {
-            val callActivity: VectorCallActivity = viewModelContext.activity()
-            return callActivity.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<VectorCallViewModel, VectorCallViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt b/vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt
index 0a63ad6907..0d8e538eca 100644
--- a/vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt
+++ b/vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt
@@ -20,9 +20,8 @@ import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import androidx.localbroadcastmanager.content.LocalBroadcastManager
 import com.facebook.react.bridge.JavaOnlyMap
 import org.jitsi.meet.sdk.BroadcastEmitter
@@ -42,7 +41,7 @@ sealed class ConferenceEvent(open val data: Map<String, Any>) {
     }
 }
 
-class ConferenceEventEmitter(private val context: Context)  {
+class ConferenceEventEmitter(private val context: Context) {
 
     fun emitConferenceEnded() {
         val broadcastEventData = JavaOnlyMap.of(CONFERENCE_URL_DATA_KEY, JitsiMeet.getCurrentConference())
@@ -52,7 +51,7 @@ class ConferenceEventEmitter(private val context: Context)  {
 
 class ConferenceEventObserver(private val context: Context,
                               private val onBroadcastEvent: (ConferenceEvent) -> Unit) :
-    LifecycleObserver {
+        DefaultLifecycleObserver {
 
     // See https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk#listening-for-broadcasted-events
     private val broadcastReceiver = object : BroadcastReceiver() {
@@ -61,8 +60,7 @@ class ConferenceEventObserver(private val context: Context,
         }
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-    fun unregisterForBroadcastMessages() {
+    override fun onDestroy(owner: LifecycleOwner) {
         try {
             LocalBroadcastManager.getInstance(context).unregisterReceiver(broadcastReceiver)
         } catch (throwable: Throwable) {
@@ -70,8 +68,7 @@ class ConferenceEventObserver(private val context: Context,
         }
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
-    fun registerForBroadcastMessages() {
+    override fun onCreate(owner: LifecycleOwner) {
         val intentFilter = IntentFilter()
         for (type in BroadcastEvent.Type.values()) {
             intentFilter.addAction(type.action)
diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt
index c46b4e459d..d04bebfd1b 100644
--- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt
@@ -22,10 +22,11 @@ import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.Job
@@ -46,8 +47,8 @@ class JitsiCallViewModel @AssistedInject constructor(
 ) : VectorViewModel<JitsiCallViewState, JitsiCallViewActions, JitsiCallViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: JitsiCallViewState): JitsiCallViewModel
+    interface Factory : MavericksAssistedViewModelFactory<JitsiCallViewModel, JitsiCallViewState> {
+        override fun create(initialState: JitsiCallViewState): JitsiCallViewModel
     }
 
     private var currentWidgetObserver: Job? = null
@@ -143,24 +144,7 @@ class JitsiCallViewModel @AssistedInject constructor(
         }
     }
 
-    companion object : MavericksViewModelFactory<JitsiCallViewModel, JitsiCallViewState> {
-
+    companion object : MavericksViewModelFactory<JitsiCallViewModel, JitsiCallViewState> by hiltMavericksViewModelFactory() {
         const val ENABLE_VIDEO_OPTION = "ENABLE_VIDEO_OPTION"
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: JitsiCallViewState): JitsiCallViewModel? {
-            val callActivity: VectorJitsiActivity = viewModelContext.activity()
-            return callActivity.viewModelFactory.create(state)
-        }
-
-        override fun initialState(viewModelContext: ViewModelContext): JitsiCallViewState? {
-            val args: VectorJitsiActivity.Args = viewModelContext.args()
-
-            return JitsiCallViewState(
-                    roomId = args.roomId,
-                    widgetId = args.widgetId,
-                    enableVideo = args.enableVideo
-            )
-        }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt
index d4c70d7333..7ecd44b9b0 100644
--- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt
@@ -26,4 +26,11 @@ data class JitsiCallViewState(
         val widgetId: String = "",
         val enableVideo: Boolean = false,
         val widget: Async<Widget> = Uninitialized
-) : MavericksState
+) : MavericksState {
+
+    constructor(args: VectorJitsiActivity.Args) : this(
+            roomId = args.roomId,
+            widgetId = args.widgetId,
+            enableVideo = args.enableVideo
+    )
+}
diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt
index 62d017467f..0fdfea8bff 100644
--- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt
@@ -33,8 +33,8 @@ import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.viewModel
 import com.facebook.react.modules.core.PermissionListener
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityJitsiBinding
@@ -48,8 +48,8 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.util.JsonDict
 import timber.log.Timber
 import java.net.URL
-import javax.inject.Inject
 
+@AndroidEntryPoint
 class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMeetActivityInterface {
 
     @Parcelize
@@ -61,20 +61,14 @@ class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMee
 
     override fun getBinding() = ActivityJitsiBinding.inflate(layoutInflater)
 
-    @Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
-
     private var jitsiMeetView: JitsiMeetView? = null
 
     private val jitsiViewModel: JitsiCallViewModel by viewModel()
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        jitsiViewModel.subscribe(this) {
+        jitsiViewModel.onEach {
             renderState(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt b/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt
index 5a1d8cd396..161aa33d1d 100644
--- a/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt
+++ b/vector/src/main/java/im/vector/app/features/call/service/CallHeadsUpActionReceiver.kt
@@ -19,7 +19,7 @@ package im.vector.app.features.call.service
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
-import im.vector.app.core.di.HasVectorInjector
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.features.call.webrtc.WebRtcCallManager
 import timber.log.Timber
 
@@ -32,11 +32,7 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() {
     }
 
     override fun onReceive(context: Context, intent: Intent?) {
-        val webRtcCallManager = (context.applicationContext as? HasVectorInjector)
-                ?.injector()
-                ?.webRtcCallManager()
-                ?: return
-
+        val webRtcCallManager = context.singletonEntryPoint().webRtcCallManager()
         when (intent?.getIntExtra(EXTRA_CALL_ACTION_KEY, 0)) {
             CALL_ACTION_REJECT -> {
                 val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: return
diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt
index 2a50dc85f9..c03b526f8c 100644
--- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt
@@ -23,15 +23,11 @@ import android.os.Parcelable
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.tabs.TabLayoutMediator
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityCallTransferBinding
-import im.vector.app.features.contactsbook.ContactsBookViewModel
-import im.vector.app.features.contactsbook.ContactsBookViewState
-import im.vector.app.features.userdirectory.UserListViewModel
-import im.vector.app.features.userdirectory.UserListViewState
 import kotlinx.parcelize.Parcelize
 import javax.inject.Inject
 
@@ -40,14 +36,9 @@ data class CallTransferArgs(val callId: String) : Parcelable
 
 private const val USER_LIST_FRAGMENT_TAG = "USER_LIST_FRAGMENT_TAG"
 
-class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
-        CallTransferViewModel.Factory,
-        UserListViewModel.Factory,
-        ContactsBookViewModel.Factory {
+@AndroidEntryPoint
+class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>() {
 
-    @Inject lateinit var userListViewModelFactory: UserListViewModel.Factory
-    @Inject lateinit var callTransferViewModelFactory: CallTransferViewModel.Factory
-    @Inject lateinit var contactsBookViewModelFactory: ContactsBookViewModel.Factory
     @Inject lateinit var errorFormatter: ErrorFormatter
 
     private lateinit var sectionsPagerAdapter: CallTransferPagerAdapter
@@ -58,22 +49,6 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
 
     override fun getCoordinatorLayout() = views.vectorCoordinatorLayout
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
-    override fun create(initialState: UserListViewState): UserListViewModel {
-        return userListViewModelFactory.create(initialState)
-    }
-
-    override fun create(initialState: CallTransferViewState): CallTransferViewModel {
-        return callTransferViewModelFactory.create(initialState)
-    }
-
-    override fun create(initialState: ContactsBookViewState): ContactsBookViewModel {
-        return contactsBookViewModelFactory.create(initialState)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         waitingView = views.waitingView.waitingView
diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt
index a26b03a3aa..ffc6ff9bc3 100644
--- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt
@@ -16,13 +16,12 @@
 
 package im.vector.app.features.call.transfer
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.call.dialpad.DialPadLookup
@@ -41,18 +40,11 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState:
     VectorViewModel<CallTransferViewState, CallTransferAction, CallTransferViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: CallTransferViewState): CallTransferViewModel
+    interface Factory : MavericksAssistedViewModelFactory<CallTransferViewModel, CallTransferViewState> {
+        override fun create(initialState: CallTransferViewState): CallTransferViewModel
     }
 
-    companion object : MavericksViewModelFactory<CallTransferViewModel, CallTransferViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: CallTransferViewState): CallTransferViewModel? {
-            val activity: CallTransferActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.callTransferViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<CallTransferViewModel, CallTransferViewState> by hiltMavericksViewModelFactory()
 
     private val call = callManager.getCallById(initialState.callId)
     private val callListener = object : WebRtcCall.Listener {
diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
index e632d00790..bbb158f6e4 100644
--- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
+++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
@@ -19,8 +19,10 @@ package im.vector.app.features.call.webrtc
 import android.content.Context
 import android.hardware.camera2.CameraManager
 import androidx.core.content.getSystemService
+import im.vector.app.core.flow.chunk
 import im.vector.app.core.services.CallService
 import im.vector.app.core.utils.CountUpTimer
+import im.vector.app.core.utils.PublishDataSource
 import im.vector.app.core.utils.TextUtils.formatDuration
 import im.vector.app.features.call.CameraEventsHandlerAdapter
 import im.vector.app.features.call.CameraProxy
@@ -35,14 +37,16 @@ import im.vector.app.features.call.utils.awaitSetLocalDescription
 import im.vector.app.features.call.utils.awaitSetRemoteDescription
 import im.vector.app.features.call.utils.mapToCallCandidate
 import im.vector.app.features.session.coroutineScope
-import io.reactivex.disposables.Disposable
-import io.reactivex.subjects.PublishSubject
-import io.reactivex.subjects.ReplaySubject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.async
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.extensions.orFalse
@@ -85,7 +89,6 @@ import org.webrtc.VideoTrack
 import timber.log.Timber
 import java.lang.ref.WeakReference
 import java.util.concurrent.CopyOnWriteArrayList
-import java.util.concurrent.TimeUnit
 import javax.inject.Provider
 import kotlin.coroutines.CoroutineContext
 
@@ -157,7 +160,7 @@ class WebRtcCall(
     private var currentCaptureFormat: CaptureFormat = CaptureFormat.HD
     private var cameraAvailabilityCallback: CameraManager.AvailabilityCallback? = null
 
-    private val timer = CountUpTimer(Duration.ofSeconds(1).toMillis()).apply {
+    private val timer = CountUpTimer(1000L).apply {
         tickListener = object : CountUpTimer.TickListener {
             override fun onTick(milliseconds: Long) {
                 val formattedDuration = formatDuration(Duration.ofMillis(milliseconds))
@@ -197,26 +200,33 @@ class WebRtcCall(
     private var localSurfaceRenderers: MutableList<WeakReference<SurfaceViewRenderer>> = ArrayList()
     private var remoteSurfaceRenderers: MutableList<WeakReference<SurfaceViewRenderer>> = ArrayList()
 
-    private val iceCandidateSource: PublishSubject<IceCandidate> = PublishSubject.create()
-    private val iceCandidateDisposable = iceCandidateSource
-            .buffer(300, TimeUnit.MILLISECONDS)
-            .subscribe {
-                // omit empty :/
-                if (it.isNotEmpty()) {
-                    Timber.tag(loggerTag.value).v("Sending local ice candidates to call")
-                    // it.forEach { peerConnection?.addIceCandidate(it) }
-                    mxCall.sendLocalCallCandidates(it.mapToCallCandidate())
-                }
-            }
+    private val localIceCandidateSource = PublishDataSource<IceCandidate>()
+    private var localIceCandidateJob: Job? = null
 
-    private val remoteCandidateSource: ReplaySubject<IceCandidate> = ReplaySubject.create()
-    private var remoteIceCandidateDisposable: Disposable? = null
+    private val remoteCandidateSource: MutableSharedFlow<IceCandidate> = MutableSharedFlow(replay = Int.MAX_VALUE)
+    private var remoteIceCandidateJob: Job? = null
 
     init {
+        setupLocalIceCanditate()
         mxCall.addListener(this)
     }
 
-    fun onIceCandidate(iceCandidate: IceCandidate) = iceCandidateSource.onNext(iceCandidate)
+    private fun setupLocalIceCanditate() {
+        sessionScope?.let {
+            localIceCandidateJob = localIceCandidateSource.stream()
+                    .chunk(300)
+                    .onEach {
+                        // omit empty :/
+                        if (it.isNotEmpty()) {
+                            Timber.tag(loggerTag.value).v("Sending local ice candidates to call")
+                            // it.forEach { peerConnection?.addIceCandidate(it) }
+                            mxCall.sendLocalCallCandidates(it.mapToCallCandidate())
+                        }
+                    }.launchIn(it)
+        }
+    }
+
+    fun onIceCandidate(iceCandidate: IceCandidate) = localIceCandidateSource.post(iceCandidate)
 
     fun onRenegotiationNeeded(restartIce: Boolean) {
         sessionScope?.launch(dispatcher) {
@@ -438,12 +448,15 @@ class WebRtcCall(
         createLocalStream()
         attachViewRenderersInternal()
         Timber.tag(loggerTag.value).v("remoteCandidateSource $remoteCandidateSource")
-        remoteIceCandidateDisposable = remoteCandidateSource.subscribe({
-            Timber.tag(loggerTag.value).v("adding remote ice candidate $it")
-            peerConnection?.addIceCandidate(it)
-        }, {
-            Timber.tag(loggerTag.value).v("failed to add remote ice candidate $it")
-        })
+        remoteIceCandidateJob = remoteCandidateSource
+                .onEach {
+                    Timber.tag(loggerTag.value).v("adding remote ice candidate $it")
+                    peerConnection?.addIceCandidate(it)
+                }
+                .catch {
+                    Timber.tag(loggerTag.value).v("failed to add remote ice candidate $it")
+                }
+                .launchIn(this)
         // Now we wait for negotiation callback
     }
 
@@ -488,12 +501,13 @@ class WebRtcCall(
             mxCall.accept(it.description)
         }
         Timber.tag(loggerTag.value).v("remoteCandidateSource $remoteCandidateSource")
-        remoteIceCandidateDisposable = remoteCandidateSource.subscribe({
-            Timber.tag(loggerTag.value).v("adding remote ice candidate $it")
-            peerConnection?.addIceCandidate(it)
-        }, {
-            Timber.tag(loggerTag.value).v("failed to add remote ice candidate $it")
-        })
+        remoteIceCandidateJob = remoteCandidateSource
+                .onEach {
+                    Timber.tag(loggerTag.value).v("adding remote ice candidate $it")
+                    peerConnection?.addIceCandidate(it)
+                }.catch {
+                    Timber.tag(loggerTag.value).v("failed to add remote ice candidate $it")
+                }.launchIn(this)
     }
 
     private suspend fun getTurnServer(): TurnServerResponse? {
@@ -761,8 +775,8 @@ class WebRtcCall(
         videoCapturer?.stopCapture()
         videoCapturer?.dispose()
         videoCapturer = null
-        remoteIceCandidateDisposable?.dispose()
-        iceCandidateDisposable?.dispose()
+        remoteIceCandidateJob?.cancel()
+        localIceCandidateJob?.cancel()
         peerConnection?.close()
         peerConnection?.dispose()
         localAudioSource?.dispose()
@@ -852,7 +866,7 @@ class WebRtcCall(
                 }
                 Timber.tag(loggerTag.value).v("onCallIceCandidateReceived for call ${mxCall.callId} sdp: ${it.candidate}")
                 val iceCandidate = IceCandidate(it.sdpMid, it.sdpMLineIndex, it.candidate)
-                remoteCandidateSource.onNext(iceCandidate)
+                remoteCandidateSource.emit(iceCandidate)
             }
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt
index e9fdd5d26a..6b337020a5 100644
--- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt
+++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt
@@ -17,9 +17,8 @@
 package im.vector.app.features.call.webrtc
 
 import android.content.Context
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import im.vector.app.ActiveSessionDataSource
 import im.vector.app.BuildConfig
 import im.vector.app.core.services.CallService
@@ -70,7 +69,8 @@ private val loggerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP)
 class WebRtcCallManager @Inject constructor(
         private val context: Context,
         private val activeSessionDataSource: ActiveSessionDataSource
-) : CallListener, LifecycleObserver {
+) : CallListener,
+        DefaultLifecycleObserver {
 
     private val currentSession: Session?
         get() = activeSessionDataSource.currentValue?.orNull()
@@ -133,13 +133,11 @@ class WebRtcCallManager @Inject constructor(
 
     private var isInBackground: Boolean = true
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
-    fun entersForeground() {
+    override fun onResume(owner: LifecycleOwner) {
         isInBackground = false
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
-    fun entersBackground() {
+    override fun onPause(owner: LifecycleOwner) {
         isInBackground = true
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt
index ccabd25ff4..1950038691 100644
--- a/vector/src/main/java/im/vector/app/features/command/Command.kt
+++ b/vector/src/main/java/im/vector/app/features/command/Command.kt
@@ -47,7 +47,6 @@ enum class Command(val command: String, val parameters: String, @StringRes val d
     RAINBOW_EMOTE("/rainbowme", "<message>", R.string.command_description_rainbow_emote, false),
     CLEAR_SCALAR_TOKEN("/clear_scalar_token", "", R.string.command_description_clear_scalar_token, false),
     SPOILER("/spoiler", "<message>", R.string.command_description_spoiler, false),
-    POLL("/poll", "Question | Option 1 | Option 2 ...", R.string.command_description_poll, false),
     SHRUG("/shrug", "<message>", R.string.command_description_shrug, false),
     LENNY("/lenny", "<message>", R.string.command_description_lenny, false),
     PLAIN("/plain", "<message>", R.string.command_description_plain, false),
diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt
index 3a6b005d6f..4b2a4aa28c 100644
--- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt
+++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt
@@ -345,15 +345,6 @@ object CommandParser {
 
                     ParsedCommand.SendLenny(message)
                 }
-                Command.POLL.command                         -> {
-                    val rawCommand = textMessage.substring(Command.POLL.command.length).trim()
-                    val split = rawCommand.split("|").map { it.trim() }
-                    if (split.size > 2) {
-                        ParsedCommand.SendPoll(split[0], split.subList(1, split.size))
-                    } else {
-                        ParsedCommand.ErrorSyntax(Command.POLL)
-                    }
-                }
                 Command.DISCARD_SESSION.command              -> {
                     ParsedCommand.DiscardSession
                 }
diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt
index 89aa8d9188..4f8d19abb6 100644
--- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt
+++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt
@@ -61,7 +61,6 @@ sealed class ParsedCommand {
     class SendSpoiler(val message: String) : ParsedCommand()
     class SendShrug(val message: CharSequence) : ParsedCommand()
     class SendLenny(val message: CharSequence) : ParsedCommand()
-    class SendPoll(val question: String, val options: List<String>) : ParsedCommand()
     object DiscardSession : ParsedCommand()
     class ShowUser(val userId: String) : ParsedCommand()
     class SendChatEffect(val chatEffect: ChatEffect, val message: String) : ParsedCommand()
diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt
index ea1841d870..95c6105912 100644
--- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookFragment.kt
@@ -21,10 +21,9 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.widget.checkedChanges
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.extensions.hideKeyboard
@@ -37,15 +36,18 @@ import im.vector.app.features.userdirectory.UserListAction
 import im.vector.app.features.userdirectory.UserListSharedAction
 import im.vector.app.features.userdirectory.UserListSharedActionViewModel
 import im.vector.app.features.userdirectory.UserListViewModel
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.identity.ThreePid
 import org.matrix.android.sdk.api.session.user.model.User
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.android.widget.checkedChanges
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class ContactsBookFragment @Inject constructor(
-        private val contactsBookViewModelFactory: ContactsBookViewModel.Factory,
         private val contactsBookController: ContactsBookController
-) : VectorBaseFragment<FragmentContactsBookBinding>(), ContactsBookController.Callback, ContactsBookViewModel.Factory {
+) : VectorBaseFragment<FragmentContactsBookBinding>(), ContactsBookController.Callback {
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentContactsBookBinding {
         return FragmentContactsBookBinding.inflate(inflater, container, false)
@@ -58,10 +60,6 @@ class ContactsBookFragment @Inject constructor(
 
     private lateinit var sharedActionViewModel: UserListSharedActionViewModel
 
-    override fun create(initialState: ContactsBookViewState): ContactsBookViewModel {
-        return contactsBookViewModelFactory.create(initialState)
-    }
-
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         sharedActionViewModel = activityViewModelProvider.get(UserListSharedActionViewModel::class.java)
@@ -88,21 +86,21 @@ class ContactsBookFragment @Inject constructor(
 
     private fun setupOnlyBoundContactsView() {
         views.phoneBookOnlyBoundContacts.checkedChanges()
-                .subscribe {
+                .onEach {
                     contactsBookViewModel.handle(ContactsBookAction.OnlyBoundContacts(it))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun setupFilterView() {
         views.phoneBookFilter
                 .textChanges()
                 .skipInitialValue()
-                .debounce(300, TimeUnit.MILLISECONDS)
-                .subscribe {
+                .debounce(300)
+                .onEach {
                     contactsBookViewModel.handle(ContactsBookAction.FilterWith(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun onDestroyView() {
diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt
index 6b5a6465a6..7f0dbcb7b2 100644
--- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt
@@ -17,17 +17,16 @@
 package im.vector.app.features.contactsbook
 
 import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.core.contacts.ContactsDataSource
 import im.vector.app.core.contacts.MappedContact
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -45,20 +44,11 @@ class ContactsBookViewModel @AssistedInject constructor(@Assisted
     VectorViewModel<ContactsBookViewState, ContactsBookAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ContactsBookViewState): ContactsBookViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ContactsBookViewModel, ContactsBookViewState> {
+        override fun create(initialState: ContactsBookViewState): ContactsBookViewModel
     }
 
-    companion object : MavericksViewModelFactory<ContactsBookViewModel, ContactsBookViewState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: ContactsBookViewState): ContactsBookViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<ContactsBookViewModel, ContactsBookViewState> by hiltMavericksViewModelFactory()
 
     private var allContacts: List<MappedContact> = emptyList()
     private var mappedContacts: List<MappedContact> = emptyList()
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
index ae3af4b3e9..3ff989da5a 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
@@ -22,14 +22,15 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.view.View
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
@@ -42,47 +43,32 @@ import im.vector.app.core.utils.checkPermissions
 import im.vector.app.core.utils.onPermissionDeniedSnackbar
 import im.vector.app.core.utils.registerForPermissionsResult
 import im.vector.app.features.contactsbook.ContactsBookFragment
-import im.vector.app.features.contactsbook.ContactsBookViewModel
-import im.vector.app.features.contactsbook.ContactsBookViewState
 import im.vector.app.features.userdirectory.UserListFragment
 import im.vector.app.features.userdirectory.UserListFragmentArgs
 import im.vector.app.features.userdirectory.UserListSharedAction
 import im.vector.app.features.userdirectory.UserListSharedActionViewModel
-import im.vector.app.features.userdirectory.UserListViewModel
-import im.vector.app.features.userdirectory.UserListViewState
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import java.net.HttpURLConnection
 import javax.inject.Inject
 
-class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Factory, CreateDirectRoomViewModel.Factory, ContactsBookViewModel.Factory {
+@AndroidEntryPoint
+class CreateDirectRoomActivity : SimpleFragmentActivity() {
 
     private val viewModel: CreateDirectRoomViewModel by viewModel()
     private lateinit var sharedActionViewModel: UserListSharedActionViewModel
-    @Inject lateinit var userListViewModelFactory: UserListViewModel.Factory
-    @Inject lateinit var createDirectRoomViewModelFactory: CreateDirectRoomViewModel.Factory
-    @Inject lateinit var contactsBookViewModelFactory: ContactsBookViewModel.Factory
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
-    override fun create(initialState: UserListViewState) = userListViewModelFactory.create(initialState)
-
-    override fun create(initialState: CreateDirectRoomViewState) = createDirectRoomViewModelFactory.create(initialState)
-
-    override fun create(initialState: ContactsBookViewState) = contactsBookViewModelFactory.create(initialState)
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         views.toolbar.visibility = View.GONE
 
         sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
         sharedActionViewModel
-                .observe()
-                .subscribe { action ->
+                .stream()
+                .onEach { action ->
                     when (action) {
                         UserListSharedAction.Close                 -> finish()
                         UserListSharedAction.GoBack                -> onBackPressed()
@@ -91,7 +77,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac
                         UserListSharedAction.AddByQrCode           -> openAddByQrCode()
                     }.exhaustive
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
         if (isFirstCreation()) {
             addFragment(
                     R.id.container,
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
index 347dcdc410..41360eab93 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt
@@ -16,16 +16,14 @@
 
 package im.vector.app.features.createdirect
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.mvrx.runCatchingToAsync
 import im.vector.app.core.platform.VectorViewModel
@@ -45,21 +43,11 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
     VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction, CreateDirectRoomViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: CreateDirectRoomViewState): CreateDirectRoomViewModel
+    interface Factory : MavericksAssistedViewModelFactory<CreateDirectRoomViewModel, CreateDirectRoomViewState> {
+        override fun create(initialState: CreateDirectRoomViewState): CreateDirectRoomViewModel
     }
 
-    companion object : MavericksViewModelFactory<CreateDirectRoomViewModel, CreateDirectRoomViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: CreateDirectRoomViewState): CreateDirectRoomViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<CreateDirectRoomViewModel, CreateDirectRoomViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: CreateDirectRoomAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt
index e80853b035..bdae975846 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt
@@ -19,7 +19,9 @@ import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
+import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.extensions.addFragmentToBackstack
 import im.vector.app.core.extensions.observeEvent
 import im.vector.app.core.extensions.registerStartForActivityResult
@@ -28,7 +30,9 @@ import im.vector.app.core.platform.SimpleFragmentActivity
 import im.vector.app.core.ui.views.KeysBackupBanner
 import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
 import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
+import javax.inject.Inject
 
+@AndroidEntryPoint
 class KeysBackupRestoreActivity : SimpleFragmentActivity() {
 
     companion object {
@@ -48,10 +52,12 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
         super.onBackPressed()
     }
 
+    @Inject  lateinit var activeSessionHolder: ActiveSessionHolder
+
     override fun initUiAndData() {
         super.initUiAndData()
         viewModel = viewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
-        viewModel.initSession(session)
+        viewModel.initSession(activeSessionHolder.getActiveSession())
 
         viewModel.keySourceModel.observe(this) { keySource ->
             if (keySource != null && !keySource.isInQuadS && supportFragmentManager.fragments.isEmpty()) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt
index ddbe86305c..a0a6a138dc 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt
@@ -29,13 +29,8 @@ class KeysBackupRestoreFromKeyViewModel @Inject constructor(
         private val stringProvider: StringProvider
 ) : ViewModel() {
 
-    var recoveryCode: MutableLiveData<String> = MutableLiveData()
-    var recoveryCodeErrorText: MutableLiveData<String> = MutableLiveData()
-
-    init {
-        recoveryCode.value = null
-        recoveryCodeErrorText.value = null
-    }
+    var recoveryCode: MutableLiveData<String?> = MutableLiveData(null)
+    var recoveryCodeErrorText: MutableLiveData<String?> = MutableLiveData(null)
 
     // ========= Actions =========
     fun updateCode(newValue: String) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt
index af5938e20a..81d3c64dec 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt
@@ -28,13 +28,8 @@ class KeysBackupRestoreFromPassphraseViewModel @Inject constructor(
         private val stringProvider: StringProvider
 ) : ViewModel() {
 
-    var passphrase: MutableLiveData<String> = MutableLiveData()
-    var passphraseErrorText: MutableLiveData<String> = MutableLiveData()
-
-    init {
-        passphrase.value = null
-        passphraseErrorText.value = null
-    }
+    var passphrase: MutableLiveData<String?> = MutableLiveData(null)
+    var passphraseErrorText: MutableLiveData<String?> = MutableLiveData(null)
 
     // ========= Actions =========
 
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt
index 34a333d588..8362a3566e 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt
@@ -57,7 +57,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
 
     lateinit var session: Session
 
-    var keyVersionResult: MutableLiveData<KeysVersionResult> = MutableLiveData()
+    var keyVersionResult: MutableLiveData<KeysVersionResult?> = MutableLiveData(null)
 
     var keySourceModel: MutableLiveData<KeySource> = MutableLiveData()
 
@@ -69,17 +69,11 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
     val navigateEvent: LiveData<LiveEvent<String>>
         get() = _navigateEvent
 
-    var loadingEvent: MutableLiveData<WaitingViewData> = MutableLiveData()
+    var loadingEvent: MutableLiveData<WaitingViewData?> = MutableLiveData(null)
 
     var importKeyResult: ImportRoomKeysResult? = null
     var importRoomKeysFinishWithResult: MutableLiveData<LiveEvent<ImportRoomKeysResult>> = MutableLiveData()
 
-    init {
-        keyVersionResult.value = null
-        _keyVersionResultError.value = null
-        loadingEvent.value = null
-    }
-
     fun initSession(session: Session) {
         this.session = session
     }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt
index 716f02369a..2b666e9cf8 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt
@@ -21,13 +21,13 @@ import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.platform.SimpleFragmentActivity
 import im.vector.app.core.platform.WaitingViewData
-import javax.inject.Inject
 
+@AndroidEntryPoint
 class KeysBackupManageActivity : SimpleFragmentActivity() {
 
     companion object {
@@ -40,12 +40,6 @@ class KeysBackupManageActivity : SimpleFragmentActivity() {
     override fun getTitleRes() = R.string.encryption_message_recovery
 
     private val viewModel: KeysBackupSettingsViewModel by viewModel()
-    @Inject lateinit var keysBackupSettingsViewModelFactory: KeysBackupSettingsViewModel.Factory
-
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
 
     override fun initUiAndData() {
         super.initUiAndData()
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt
index 6814b376c2..d6d9e10669 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt
@@ -15,16 +15,16 @@
  */
 package im.vector.app.features.crypto.keysbackup.settings
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import org.matrix.android.sdk.api.MatrixCallback
@@ -41,18 +41,11 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
         KeysBackupStateListener {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: KeysBackupSettingViewState): KeysBackupSettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<KeysBackupSettingsViewModel, KeysBackupSettingViewState> {
+        override fun create(initialState: KeysBackupSettingViewState): KeysBackupSettingsViewModel
     }
 
-    companion object : MavericksViewModelFactory<KeysBackupSettingsViewModel, KeysBackupSettingViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: KeysBackupSettingViewState): KeysBackupSettingsViewModel? {
-            val activity: KeysBackupManageActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.keysBackupSettingsViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<KeysBackupSettingsViewModel, KeysBackupSettingViewState> by hiltMavericksViewModelFactory()
 
     private val keysBackupService: KeysBackupService = session.cryptoService().keysBackupService()
 
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt
index 7cc46ef62c..0f7c09ca16 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt
@@ -23,8 +23,9 @@ import androidx.core.view.isVisible
 import androidx.fragment.app.FragmentManager
 import androidx.lifecycle.lifecycleScope
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
+import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.dialogs.ExportKeysDialog
 import im.vector.app.core.extensions.observeEvent
 import im.vector.app.core.extensions.queryExportKeys
@@ -36,6 +37,7 @@ import im.vector.app.features.crypto.keys.KeysExporter
 import kotlinx.coroutines.launch
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class KeysBackupSetupActivity : SimpleFragmentActivity() {
 
     override fun getTitleRes() = R.string.title_activity_keys_backup_setup
@@ -43,10 +45,10 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
     private lateinit var viewModel: KeysBackupSetupSharedViewModel
 
     @Inject lateinit var keysExporter: KeysExporter
+    @Inject lateinit var activeSessionHolder: ActiveSessionHolder
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
+    private val session by lazy {
+        activeSessionHolder.getActiveSession()
     }
 
     override fun initUiAndData() {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt
index cd59a69a86..1141886689 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt
@@ -68,23 +68,15 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
     // Step 3
     // Var to ignore events from previous request(s) to generate a recovery key
     private var currentRequestId: MutableLiveData<Long> = MutableLiveData()
-    var recoveryKey: MutableLiveData<String> = MutableLiveData()
-    var prepareRecoverFailError: MutableLiveData<Throwable> = MutableLiveData()
+    var recoveryKey: MutableLiveData<String?> = MutableLiveData(null)
+    var prepareRecoverFailError: MutableLiveData<Throwable?> = MutableLiveData(null)
     var megolmBackupCreationInfo: MegolmBackupCreationInfo? = null
     var copyHasBeenMade = false
-    var isCreatingBackupVersion: MutableLiveData<Boolean> = MutableLiveData()
-    var creatingBackupError: MutableLiveData<Throwable> = MutableLiveData()
+    var isCreatingBackupVersion: MutableLiveData<Boolean> = MutableLiveData(false)
+    var creatingBackupError: MutableLiveData<Throwable?> = MutableLiveData(null)
     var keysVersion: MutableLiveData<KeysVersion> = MutableLiveData()
 
-    var loadingStatus: MutableLiveData<WaitingViewData> = MutableLiveData()
-
-    init {
-        recoveryKey.value = null
-        isCreatingBackupVersion.value = false
-        prepareRecoverFailError.value = null
-        creatingBackupError.value = null
-        loadingStatus.value = null
-    }
+    var loadingStatus: MutableLiveData<WaitingViewData?> = MutableLiveData(null)
 
     fun initSession(session: Session) {
         this.session = session
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt
index bd7195ad1e..bb854aca26 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt
@@ -28,8 +28,8 @@ import androidx.fragment.app.FragmentOnAttachListener
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.platform.SimpleFragmentActivity
@@ -39,6 +39,7 @@ import kotlinx.parcelize.Parcelize
 import javax.inject.Inject
 import kotlin.reflect.KClass
 
+@AndroidEntryPoint
 class SharedSecureStorageActivity :
         SimpleFragmentActivity(),
         VectorBaseBottomSheetDialogFragment.ResultListener,
@@ -52,14 +53,8 @@ class SharedSecureStorageActivity :
     ) : Parcelable
 
     private val viewModel: SharedSecureStorageViewModel by viewModel()
-    @Inject lateinit var viewModelFactory: SharedSecureStorageViewModel.Factory
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         supportFragmentManager.addFragmentOnAttachListener(this)
@@ -68,7 +63,7 @@ class SharedSecureStorageActivity :
 
         viewModel.observeViewEvents { observeViewEvents(it) }
 
-        viewModel.subscribe(this) { renderState(it) }
+        viewModel.onEach { renderState(it) }
     }
 
     override fun onDestroy() {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt
index bb4d4ce99a..8994ad901b 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt
@@ -19,16 +19,16 @@ package im.vector.app.features.crypto.quads
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
-import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.platform.WaitingViewData
@@ -54,8 +54,18 @@ data class SharedSecureStorageViewState(
         val step: Step = Step.EnterPassphrase,
         val activeDeviceCount: Int = 0,
         val showResetAllAction: Boolean = false,
-        val userId: String = ""
+        val userId: String = "",
+        val keyId: String?,
+        val requestedSecrets: List<String>,
+        val resultKeyStoreAlias: String
 ) : MavericksState {
+
+    constructor(args: SharedSecureStorageActivity.Args) : this(
+            keyId = args.keyId,
+            requestedSecrets = args.requestedSecrets,
+            resultKeyStoreAlias = args.resultKeyStoreAlias
+    )
+
     enum class Step {
         EnterPassphrase,
         EnterKey,
@@ -64,23 +74,22 @@ data class SharedSecureStorageViewState(
 }
 
 class SharedSecureStorageViewModel @AssistedInject constructor(
-        @Assisted initialState: SharedSecureStorageViewState,
-        @Assisted val args: SharedSecureStorageActivity.Args,
+        @Assisted private val initialState: SharedSecureStorageViewState,
         private val stringProvider: StringProvider,
         private val session: Session) :
     VectorViewModel<SharedSecureStorageViewState, SharedSecureStorageAction, SharedSecureStorageViewEvent>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SharedSecureStorageViewState, args: SharedSecureStorageActivity.Args): SharedSecureStorageViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SharedSecureStorageViewModel, SharedSecureStorageViewState> {
+        override fun create(initialState: SharedSecureStorageViewState): SharedSecureStorageViewModel
     }
 
     init {
         setState {
             copy(userId = session.myUserId)
         }
-        val isValid = session.sharedSecretStorageService.checkShouldBeAbleToAccessSecrets(args.requestedSecrets, args.keyId) is IntegrityResult.Success
-        if (!isValid) {
+        val integrityResult = session.sharedSecretStorageService.checkShouldBeAbleToAccessSecrets(initialState.requestedSecrets, initialState.keyId)
+        if (integrityResult  !is IntegrityResult.Success) {
             _viewEvents.post(
                     SharedSecureStorageViewEvent.Error(
                             stringProvider.getString(R.string.enter_secret_storage_invalid),
@@ -88,7 +97,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                     )
             )
         }
-        val keyResult = args.keyId?.let { session.sharedSecretStorageService.getKey(it) }
+        val keyResult = initialState.keyId?.let { session.sharedSecretStorageService.getKey(it) }
                 ?: session.sharedSecretStorageService.getDefaultKey()
 
         if (!keyResult.isSuccess()) {
@@ -218,7 +227,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                 }
 
                 withContext(Dispatchers.IO) {
-                    args.requestedSecrets.forEach {
+                    initialState.requestedSecrets.forEach {
                         if (session.accountDataService().getUserAccountDataEvent(it) != null) {
                             val res = session.sharedSecretStorageService.getSecret(
                                     name = it,
@@ -235,7 +244,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                 _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading)
                 val safeForIntentCypher = ByteArrayOutputStream().also {
                     it.use {
-                        session.securelyStoreObject(decryptedSecretMap as Map<String, String>, args.resultKeyStoreAlias, it)
+                        session.securelyStoreObject(decryptedSecretMap as Map<String, String>, initialState.resultKeyStoreAlias, it)
                     }
                 }.toByteArray().toBase64NoPadding()
                 _viewEvents.post(SharedSecureStorageViewEvent.FinishSuccess(safeForIntentCypher))
@@ -287,7 +296,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                 )
 
                 withContext(Dispatchers.IO) {
-                    args.requestedSecrets.forEach {
+                    initialState.requestedSecrets.forEach {
                         if (session.accountDataService().getUserAccountDataEvent(it) != null) {
                             val res = session.sharedSecretStorageService.getSecret(
                                     name = it,
@@ -304,7 +313,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                 _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading)
                 val safeForIntentCypher = ByteArrayOutputStream().also {
                     it.use {
-                        session.securelyStoreObject(decryptedSecretMap as Map<String, String>, args.resultKeyStoreAlias, it)
+                        session.securelyStoreObject(decryptedSecretMap as Map<String, String>, initialState.resultKeyStoreAlias, it)
                     }
                 }.toByteArray().toBase64NoPadding()
                 _viewEvents.post(SharedSecureStorageViewEvent.FinishSuccess(safeForIntentCypher))
@@ -320,13 +329,5 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
         _viewEvents.post(SharedSecureStorageViewEvent.Dismiss)
     }
 
-    companion object : MavericksViewModelFactory<SharedSecureStorageViewModel, SharedSecureStorageViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SharedSecureStorageViewState): SharedSecureStorageViewModel? {
-            val activity: SharedSecureStorageActivity = viewModelContext.activity()
-            val args: SharedSecureStorageActivity.Args = activity.intent.getParcelableExtra(Mavericks.KEY_ARG) ?: error("Missing args")
-            return activity.viewModelFactory.create(state, args)
-        }
-    }
+    companion object : MavericksViewModelFactory<SharedSecureStorageViewModel, SharedSecureStorageViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
index 1ba0198cb4..c49291d6a2 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageKeyFragment.kt
@@ -22,17 +22,19 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
-import com.jakewharton.rxbinding3.widget.editorActionEvents
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.registerStartForActivityResult
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.core.utils.startImportTextFromFileIntent
 import im.vector.app.databinding.FragmentSsssAccessFromKeyBinding
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.extensions.tryOrNull
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.android.widget.editorActionEvents
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment<FragmentSsssAccessFromKeyBinding>() {
@@ -48,22 +50,21 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
         views.ssssRestoreWithKeyText.text = getString(R.string.enter_secret_storage_input_key)
 
         views.ssssKeyEnterEdittext.editorActionEvents()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .throttleFirst(300)
+                .onEach {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
                     }
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.ssssKeyEnterEdittext.textChanges()
                 .skipInitialValue()
-                .subscribe {
+                .onEach {
                     views.ssssKeyEnterTil.error = null
                     views.ssssKeySubmit.isEnabled = it.isNotBlank()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.ssssKeyUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
 
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
index 800b02a936..c93e562d77 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStoragePassphraseFragment.kt
@@ -22,15 +22,17 @@ import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.core.text.toSpannable
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
-import com.jakewharton.rxbinding3.widget.editorActionEvents
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.core.resources.ColorProvider
 import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
-import io.reactivex.android.schedulers.AndroidSchedulers
-import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.editorActionEvents
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class SharedSecuredStoragePassphraseFragment @Inject constructor(
@@ -60,21 +62,20 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
         // .colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
 
         views.ssssPassphraseEnterEdittext.editorActionEvents()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .throttleFirst(300)
+                .onEach {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
                     }
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.ssssPassphraseEnterEdittext.textChanges()
-                .subscribe {
+                .onEach {
                     views.ssssPassphraseEnterTil.error = null
                     views.ssssPassphraseSubmit.isEnabled = it.isNotBlank()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.ssssPassphraseReset.views.bottomSheetActionClickableZone.debouncedClicks {
             sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt
index 670e5c610a..200b2b73c2 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecuredStorageResetAllFragment.kt
@@ -55,7 +55,7 @@ class SharedSecuredStorageResetAllFragment @Inject constructor() :
             }
         }
 
-        sharedViewModel.subscribe(this) { state ->
+        sharedViewModel.onEach { state ->
             views.ssssResetOtherDevices.setTextOrHide(
                     state.activeDeviceCount
                             .takeIf { it > 0 }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt
index a42c3d2dda..50f9526da5 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt
@@ -33,8 +33,8 @@ import androidx.fragment.app.FragmentManager
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.registerStartForActivityResult
@@ -43,9 +43,9 @@ import im.vector.app.databinding.BottomSheetBootstrapBinding
 import im.vector.app.features.auth.ReAuthActivity
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
-import javax.inject.Inject
 import kotlin.reflect.KClass
 
+@AndroidEntryPoint
 class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBootstrapBinding>() {
 
     @Parcelize
@@ -55,15 +55,8 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
 
     override val showExpanded = true
 
-    @Inject
-    lateinit var bootstrapViewModelFactory: BootstrapSharedViewModel.Factory
-
     private val viewModel by fragmentViewModel(BootstrapSharedViewModel::class)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetBootstrapBinding {
         return BottomSheetBootstrapBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
index 4aeb822bbd..940a4d9af3 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
@@ -22,16 +22,18 @@ import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.core.view.isGone
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.parentFragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.widget.editorActionEvents
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
-import io.reactivex.android.schedulers.AndroidSchedulers
-import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.editorActionEvents
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class BootstrapConfirmPassphraseFragment @Inject constructor() :
@@ -58,21 +60,20 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() :
         }
 
         views.ssssPassphraseEnterEdittext.editorActionEvents()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .throttleFirst(300)
+                .onEach {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
                     }
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.ssssPassphraseEnterEdittext.textChanges()
-                .subscribe {
+                .onEach {
                     views.ssssPassphraseEnterTil.error = null
-                    sharedViewModel.handle(BootstrapActions.UpdateConfirmCandidatePassphrase(it?.toString() ?: ""))
+                    sharedViewModel.handle(BootstrapActions.UpdateConfirmCandidatePassphrase(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         sharedViewModel.observeViewEvents {
             //            when (it) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
index f43ddb8888..77fb5ab3a6 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
@@ -21,16 +21,18 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.parentFragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.widget.editorActionEvents
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
 import im.vector.app.features.settings.VectorLocale
-import io.reactivex.android.schedulers.AndroidSchedulers
-import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.editorActionEvents
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class BootstrapEnterPassphraseFragment @Inject constructor() :
@@ -53,22 +55,21 @@ class BootstrapEnterPassphraseFragment @Inject constructor() :
             views.ssssPassphraseEnterEdittext.setText(it.passphrase ?: "")
         }
         views.ssssPassphraseEnterEdittext.editorActionEvents()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .throttleFirst(300)
+                .onEach {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
                     }
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.ssssPassphraseEnterEdittext.textChanges()
-                .subscribe {
+                .onEach {
                     // ssss_passphrase_enter_til.error = null
-                    sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
+                    sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it.toString()))
 //                    ssss_passphrase_submit.isEnabled = it.isNotBlank()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         sharedViewModel.observeViewEvents {
             //            when (it) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt
index b40a194a15..5d0f3bbeae 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapMigrateBackupFragment.kt
@@ -27,22 +27,24 @@ import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.core.text.toSpannable
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.parentFragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.widget.editorActionEvents
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.registerStartForActivityResult
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.core.resources.ColorProvider
 import im.vector.app.core.utils.colorizeMatchingText
 import im.vector.app.core.utils.startImportTextFromFileIntent
 import im.vector.app.databinding.FragmentBootstrapMigrateBackupBinding
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.internal.crypto.keysbackup.util.isValidRecoveryKey
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.android.widget.editorActionEvents
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class BootstrapMigrateBackupFragment @Inject constructor(
@@ -63,22 +65,21 @@ class BootstrapMigrateBackupFragment @Inject constructor(
             views.bootstrapMigrateEditText.setText(it.passphrase ?: "")
         }
         views.bootstrapMigrateEditText.editorActionEvents()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .throttleFirst(300)
+                .onEach {
                     if (it.actionId == EditorInfo.IME_ACTION_DONE) {
                         submit()
                     }
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.bootstrapMigrateEditText.textChanges()
                 .skipInitialValue()
-                .subscribe {
+                .onEach {
                     views.bootstrapRecoveryKeyEnterTil.error = null
                     // sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         // sharedViewModel.observeViewEvents {}
         views.bootstrapMigrateContinueButton.debouncedClicks { submit() }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
index d208a92545..f75ab634b8 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
@@ -16,26 +16,24 @@
 
 package im.vector.app.features.crypto.recover
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import com.nulabinc.zxcvbn.Zxcvbn
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.platform.WaitingViewData
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.auth.ReAuthActivity
-import im.vector.app.features.login.ReAuthHelper
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.auth.UIABaseAuth
@@ -59,13 +57,11 @@ import kotlin.coroutines.resumeWithException
 
 class BootstrapSharedViewModel @AssistedInject constructor(
         @Assisted initialState: BootstrapViewState,
-        @Assisted val args: BootstrapBottomSheet.Args,
         private val stringProvider: StringProvider,
         private val errorFormatter: ErrorFormatter,
         private val session: Session,
         private val bootstrapTask: BootstrapCrossSigningTask,
         private val migrationTask: BackupToQuadSMigrationTask,
-        private val reAuthHelper: ReAuthHelper
 ) : VectorViewModel<BootstrapViewState, BootstrapActions, BootstrapViewEvents>(initialState) {
 
     private var doesKeyBackupExist: Boolean = false
@@ -73,10 +69,12 @@ class BootstrapSharedViewModel @AssistedInject constructor(
     private val zxcvbn = Zxcvbn()
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: BootstrapViewState, args: BootstrapBottomSheet.Args): BootstrapSharedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<BootstrapSharedViewModel, BootstrapViewState> {
+        override fun create(initialState: BootstrapViewState): BootstrapSharedViewModel
     }
 
+    companion object : MavericksViewModelFactory<BootstrapSharedViewModel, BootstrapViewState> by hiltMavericksViewModelFactory()
+
 //    private var _pendingSession: String? = null
 
     var uiaContinuation: Continuation<UIABaseAuth>? = null
@@ -84,7 +82,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
 
     init {
 
-        when (args.setUpMode) {
+        when (initialState.setupMode) {
             SetupMode.PASSPHRASE_RESET,
             SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET,
             SetupMode.HARD_RESET         -> {
@@ -410,7 +408,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
                             progressListener = progressListener,
                             passphrase = state.passphrase,
                             keySpec = state.migrationRecoveryKey?.let { extractCurveKeyFromRecoveryKey(it)?.let { RawBytesKeySpec(it) } },
-                            setupMode = args.setUpMode
+                            setupMode = state.setupMode
                     )
             ) { bootstrapResult ->
                 when (bootstrapResult) {
@@ -516,7 +514,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
             BootstrapStep.CheckingMigration                  -> Unit
             is BootstrapStep.FirstForm                       -> {
                 _viewEvents.post(
-                        when (args.setUpMode) {
+                        when (state.setupMode) {
                             SetupMode.CROSS_SIGNING_ONLY,
                             SetupMode.NORMAL -> BootstrapViewEvents.SkipBootstrap()
                             else             -> BootstrapViewEvents.Dismiss(success = false)
@@ -547,18 +545,4 @@ class BootstrapSharedViewModel @AssistedInject constructor(
             else                                                       -> stringProvider.getString(R.string.unexpected_error)
         }
     }
-
-    // ======================================
-    // Companion, view model assisted creation
-    // ======================================
-
-    companion object : MavericksViewModelFactory<BootstrapSharedViewModel, BootstrapViewState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: BootstrapViewState): BootstrapSharedViewModel? {
-            val fragment: BootstrapBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            val args: BootstrapBottomSheet.Args = fragment.arguments?.getParcelable(BootstrapBottomSheet.EXTRA_ARGS)
-                    ?: BootstrapBottomSheet.Args(SetupMode.CROSS_SIGNING_ONLY)
-            return fragment.bootstrapViewModelFactory.create(state, args)
-        }
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt
index b8c9f10b49..9d5760cbf9 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt
@@ -24,6 +24,7 @@ import im.vector.app.core.platform.WaitingViewData
 import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo
 
 data class BootstrapViewState(
+        val setupMode: SetupMode,
         val step: BootstrapStep = BootstrapStep.CheckingMigration,
         val passphrase: String? = null,
         val migrationRecoveryKey: String? = null,
@@ -34,4 +35,7 @@ data class BootstrapViewState(
         val recoveryKeyCreationInfo: SsssKeyCreationInfo? = null,
         val initializationWaitingViewData: WaitingViewData? = null,
         val recoverySaveFileProcess: Async<Unit> = Uninitialized
-) : MavericksState
+) : MavericksState {
+
+    constructor(args: BootstrapBottomSheet.Args) : this(setupMode = args.setUpMode)
+}
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt
index e6abf13f8d..4ef0109227 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt
@@ -28,8 +28,8 @@ import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.registerStartForActivityResult
@@ -61,6 +61,7 @@ import timber.log.Timber
 import javax.inject.Inject
 import kotlin.reflect.KClass
 
+@AndroidEntryPoint
 class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetVerificationBinding>() {
 
     @Parcelize
@@ -75,18 +76,11 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
 
     override val showExpanded = true
 
-    @Inject
-    lateinit var verificationViewModelFactory: VerificationBottomSheetViewModel.Factory
-
     @Inject
     lateinit var avatarRenderer: AvatarRenderer
 
     private val viewModel by fragmentViewModel(VerificationBottomSheetViewModel::class)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding {
         return BottomSheetVerificationBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
index 702283061c..45f7f56957 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
@@ -15,20 +15,19 @@
  */
 package im.vector.app.features.crypto.verification
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -61,15 +60,17 @@ import org.matrix.android.sdk.internal.util.awaitCallback
 import timber.log.Timber
 
 data class VerificationBottomSheetViewState(
+        val otherUserId: String,
+        val verificationId: String?,
+        val roomId: String?,
+        // true when we display the loading and we wait for the other (incoming request)
+        val selfVerificationMode: Boolean,
         val otherUserMxItem: MatrixItem? = null,
-        val roomId: String? = null,
         val pendingRequest: Async<PendingVerificationRequest> = Uninitialized,
         val pendingLocalId: String? = null,
         val sasTransactionState: VerificationTxState? = null,
         val qrTransactionState: VerificationTxState? = null,
         val transactionId: String? = null,
-        // true when we display the loading and we wait for the other (incoming request)
-        val selfVerificationMode: Boolean = false,
         val verifiedFromPrivateKeys: Boolean = false,
         val verifyingFrom4S: Boolean = false,
         val isMe: Boolean = false,
@@ -79,29 +80,41 @@ data class VerificationBottomSheetViewState(
         val quadSContainsSecrets: Boolean = true,
         val quadSHasBeenReset: Boolean = false,
         val hasAnyOtherSession: Boolean = false
-) : MavericksState
+) : MavericksState {
+
+    constructor(args: VerificationBottomSheet.VerificationArgs) : this(
+            otherUserId = args.otherUserId,
+            verificationId = args.verificationId,
+            roomId = args.roomId,
+            selfVerificationMode = args.selfVerificationMode
+    )
+}
 
 class VerificationBottomSheetViewModel @AssistedInject constructor(
         @Assisted initialState: VerificationBottomSheetViewState,
-        @Assisted val args: VerificationBottomSheet.VerificationArgs,
         private val session: Session,
         private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
         private val stringProvider: StringProvider) :
-    VectorViewModel<VerificationBottomSheetViewState, VerificationAction, VerificationBottomSheetViewEvents>(initialState),
+        VectorViewModel<VerificationBottomSheetViewState, VerificationAction, VerificationBottomSheetViewEvents>(initialState),
         VerificationService.Listener {
 
+    @AssistedFactory
+    interface Factory : MavericksAssistedViewModelFactory<VerificationBottomSheetViewModel, VerificationBottomSheetViewState> {
+        override fun create(initialState: VerificationBottomSheetViewState): VerificationBottomSheetViewModel
+    }
+
+    companion object : MavericksViewModelFactory<VerificationBottomSheetViewModel, VerificationBottomSheetViewState> by hiltMavericksViewModelFactory()
+
     init {
         session.cryptoService().verificationService().addListener(this)
 
-        val userItem = session.getUser(args.otherUserId)
-
-        val selfVerificationMode = args.selfVerificationMode
+        val userItem = session.getUser(initialState.otherUserId)
 
         var autoReady = false
-        val pr = if (selfVerificationMode) {
+        val pr = if (initialState.selfVerificationMode) {
             // See if active tx for this user and take it
 
-            session.cryptoService().verificationService().getExistingVerificationRequests(args.otherUserId)
+            session.cryptoService().verificationService().getExistingVerificationRequests(initialState.otherUserId)
                     .lastOrNull { !it.isFinished }
                     ?.also { verificationRequest ->
                         if (verificationRequest.isIncoming && !verificationRequest.isReady) {
@@ -110,15 +123,15 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
                         }
                     }
         } else {
-            session.cryptoService().verificationService().getExistingVerificationRequest(args.otherUserId, args.verificationId)
+            session.cryptoService().verificationService().getExistingVerificationRequest(initialState.otherUserId, initialState.verificationId)
         }
 
-        val sasTx = (pr?.transactionId ?: args.verificationId)?.let {
-            session.cryptoService().verificationService().getExistingTransaction(args.otherUserId, it) as? SasVerificationTransaction
+        val sasTx = (pr?.transactionId ?: initialState.verificationId)?.let {
+            session.cryptoService().verificationService().getExistingTransaction(initialState.otherUserId, it) as? SasVerificationTransaction
         }
 
-        val qrTx = (pr?.transactionId ?: args.verificationId)?.let {
-            session.cryptoService().verificationService().getExistingTransaction(args.otherUserId, it) as? QrCodeVerificationTransaction
+        val qrTx = (pr?.transactionId ?: initialState.verificationId)?.let {
+            session.cryptoService().verificationService().getExistingTransaction(initialState.otherUserId, it) as? QrCodeVerificationTransaction
         }
 
         val hasAnyOtherSession = session.cryptoService()
@@ -132,11 +145,9 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
                     otherUserMxItem = userItem?.toMatrixItem(),
                     sasTransactionState = sasTx?.state,
                     qrTransactionState = qrTx?.state,
-                    transactionId = pr?.transactionId ?: args.verificationId,
+                    transactionId = pr?.transactionId ?: initialState.verificationId,
                     pendingRequest = if (pr != null) Success(pr) else Uninitialized,
-                    selfVerificationMode = selfVerificationMode,
-                    roomId = args.roomId,
-                    isMe = args.otherUserId == session.myUserId,
+                    isMe = initialState.otherUserId == session.myUserId,
                     currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(),
                     quadSContainsSecrets = session.sharedSecretStorageService.isRecoverySetup(),
                     hasAnyOtherSession = hasAnyOtherSession
@@ -159,12 +170,6 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
         super.onCleared()
     }
 
-    @AssistedFactory
-    interface Factory {
-        fun create(initialState: VerificationBottomSheetViewState,
-                   args: VerificationBottomSheet.VerificationArgs): VerificationBottomSheetViewModel
-    }
-
     fun queryCancel() = withState { state ->
         if (state.userThinkItsNotHim) {
             setState {
@@ -223,16 +228,6 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
         _viewEvents.post(VerificationBottomSheetViewEvents.GoToSettings)
     }
 
-    companion object : MavericksViewModelFactory<VerificationBottomSheetViewModel, VerificationBottomSheetViewState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: VerificationBottomSheetViewState): VerificationBottomSheetViewModel? {
-            val fragment: VerificationBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args()
-
-            return fragment.verificationViewModelFactory.create(state, args)
-        }
-    }
-
     override fun handle(action: VerificationAction) = withState { state ->
         val otherUserId = state.otherUserMxItem?.id ?: return@withState
         val roomId = state.roomId
@@ -542,7 +537,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
                 state.pendingRequest.invoke()?.transactionId == pr.transactionId) {
             setState {
                 copy(
-                        transactionId = args.verificationId ?: pr.transactionId,
+                        transactionId = state.verificationId ?: pr.transactionId,
                         pendingRequest = Success(pr)
                 )
             }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
index 92faa7a0e7..31a7956db3 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt
@@ -40,7 +40,6 @@ import timber.log.Timber
 import javax.inject.Inject
 
 class VerificationChooseMethodFragment @Inject constructor(
-        val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory,
         val controller: VerificationChooseMethodController
 ) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
         VerificationChooseMethodController.Listener {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt
index 990a204bc1..7696bb8f5b 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt
@@ -15,14 +15,16 @@
  */
 package im.vector.app.features.crypto.verification.choose
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import im.vector.app.core.di.HasScreenInjector
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.SingletonEntryPoint
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -50,6 +52,10 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
         private val session: Session
 ) : VectorViewModel<VerificationChooseMethodViewState, EmptyAction, EmptyViewEvents>(initialState), VerificationService.Listener {
 
+    init {
+        session.cryptoService().verificationService().addListener(this)
+    }
+
     override fun transactionCreated(tx: VerificationTransaction) {
         transactionUpdated(tx)
     }
@@ -81,28 +87,15 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: VerificationChooseMethodViewState): VerificationChooseMethodViewModel
+    interface Factory : MavericksAssistedViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> {
+        override fun create(initialState: VerificationChooseMethodViewState): VerificationChooseMethodViewModel
     }
 
-    init {
-        session.cryptoService().verificationService().addListener(this)
-    }
+    companion object : MavericksViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> by hiltMavericksViewModelFactory() {
 
-    override fun onCleared() {
-        session.cryptoService().verificationService().removeListener(this)
-        super.onCleared()
-    }
-
-    companion object : MavericksViewModelFactory<VerificationChooseMethodViewModel, VerificationChooseMethodViewState> {
-        override fun create(viewModelContext: ViewModelContext, state: VerificationChooseMethodViewState): VerificationChooseMethodViewModel? {
-            val fragment: VerificationChooseMethodFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.verificationChooseMethodViewModelFactory.create(state)
-        }
-
-        override fun initialState(viewModelContext: ViewModelContext): VerificationChooseMethodViewState? {
+        override fun initialState(viewModelContext: ViewModelContext): VerificationChooseMethodViewState {
             val args: VerificationBottomSheet.VerificationArgs = viewModelContext.args()
-            val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
+            val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
             val verificationService = session.cryptoService().verificationService()
             val pvr = verificationService.getExistingVerificationRequest(args.otherUserId, args.verificationId)
 
@@ -121,5 +114,10 @@ class VerificationChooseMethodViewModel @AssistedInject constructor(
         }
     }
 
+    override fun onCleared() {
+        session.cryptoService().verificationService().removeListener(this)
+        super.onCleared()
+    }
+
     override fun handle(action: EmptyAction) {}
 }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
index 566307c05b..3f4eaf8ac9 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeFragment.kt
@@ -31,7 +31,6 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheetViewMod
 import javax.inject.Inject
 
 class VerificationEmojiCodeFragment @Inject constructor(
-        val viewModelFactory: VerificationEmojiCodeViewModel.Factory,
         val controller: VerificationEmojiCodeController
 ) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
         VerificationEmojiCodeController.Listener {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt
index f1e3d1b805..6f213adb7e 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt
@@ -17,7 +17,6 @@ package im.vector.app.features.crypto.verification.emoji
 
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
@@ -27,7 +26,10 @@ import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import im.vector.app.core.di.HasScreenInjector
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.SingletonEntryPoint
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -151,20 +153,15 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel
+    interface Factory : MavericksAssistedViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> {
+        override fun create(initialState: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel
     }
 
-    companion object : MavericksViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel? {
-            val factory = (viewModelContext as FragmentViewModelContext).fragment<VerificationEmojiCodeFragment>().viewModelFactory
-            return factory.create(state)
-        }
+    companion object : MavericksViewModelFactory<VerificationEmojiCodeViewModel, VerificationEmojiCodeViewState> by hiltMavericksViewModelFactory() {
 
         override fun initialState(viewModelContext: ViewModelContext): VerificationEmojiCodeViewState? {
             val args = viewModelContext.args<VerificationBottomSheet.VerificationArgs>()
-            val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
+            val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
             val matrixItem = session.getUser(args.otherUserId)?.toMatrixItem()
 
             return VerificationEmojiCodeViewState(
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt
index 2686722c6e..2c7a15e6ad 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt
@@ -33,8 +33,8 @@ import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.extensions.toMvRxBundle
@@ -45,10 +45,9 @@ import kotlinx.parcelize.Parcelize
 import org.billcarsonfr.jsonviewer.JSonViewerFragment
 import javax.inject.Inject
 
-class RoomDevToolActivity : SimpleFragmentActivity(), RoomDevToolViewModel.Factory,
-        FragmentManager.OnBackStackChangedListener {
+@AndroidEntryPoint
+class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStackChangedListener {
 
-    @Inject lateinit var viewModelFactory: RoomDevToolViewModel.Factory
     @Inject lateinit var colorProvider: ColorProvider
 
     //    private lateinit var viewModel: RoomDevToolViewModel
@@ -65,18 +64,9 @@ class RoomDevToolActivity : SimpleFragmentActivity(), RoomDevToolViewModel.Facto
             val roomId: String
     ) : Parcelable
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
-    override fun create(initialState: RoomDevToolViewState): RoomDevToolViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
     override fun initUiAndData() {
         super.initUiAndData()
-        viewModel.subscribe(this) {
+        viewModel.onEach {
             renderState(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt
index 9af51f67b3..dd0bd174af 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolEditFragment.kt
@@ -20,12 +20,15 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentDevtoolsEditorBinding
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class RoomDevToolEditFragment @Inject constructor() :
@@ -44,10 +47,10 @@ class RoomDevToolEditFragment @Inject constructor() :
         }
         views.editText.textChanges()
                 .skipInitialValue()
-                .subscribe {
+                .onEach {
                     sharedViewModel.handle(RoomDevToolAction.UpdateContentText(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun onResume() {
diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt
index 023d1976c9..04d90a63e7 100644
--- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt
@@ -16,19 +16,17 @@
 
 package im.vector.app.features.devtools
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import com.squareup.moshi.Types
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -51,21 +49,11 @@ class RoomDevToolViewModel @AssistedInject constructor(
 ) : VectorViewModel<RoomDevToolViewState, RoomDevToolAction, DevToolsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomDevToolViewState): RoomDevToolViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomDevToolViewModel, RoomDevToolViewState> {
+        override fun create(initialState: RoomDevToolViewState): RoomDevToolViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomDevToolViewModel, RoomDevToolViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomDevToolViewState): RoomDevToolViewModel {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomDevToolViewModel, RoomDevToolViewState> by hiltMavericksViewModelFactory()
 
     init {
         session.getRoom(initialState.roomId)
diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsController.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsController.kt
index d8c67592f1..03c5d981cb 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsController.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsController.kt
@@ -95,7 +95,7 @@ class DiscoverySettingsController @Inject constructor(
         } else {
             settingsInfoItem {
                 id("idConsentInfo")
-                helperTextResId(R.string.settings_discovery_consent_notice_off)
+                helperTextResId(R.string.settings_discovery_consent_notice_off_2)
             }
             settingsButtonItem {
                 id("idConsentButton")
diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt
index 6de7c1fba5..7306146027 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt
@@ -45,8 +45,7 @@ import org.matrix.android.sdk.api.session.terms.TermsService
 import javax.inject.Inject
 
 class DiscoverySettingsFragment @Inject constructor(
-        private val controller: DiscoverySettingsController,
-        val viewModelFactory: DiscoverySettingsViewModel.Factory
+        private val controller: DiscoverySettingsController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
         DiscoverySettingsController.Listener {
 
diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt
index 66f38928a7..b02784dad9 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt
@@ -17,16 +17,16 @@ package im.vector.app.features.discovery
 
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -49,18 +49,11 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
 ) : VectorViewModel<DiscoverySettingsState, DiscoverySettingsAction, DiscoverySettingsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: DiscoverySettingsState): DiscoverySettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<DiscoverySettingsViewModel, DiscoverySettingsState> {
+        override fun create(initialState: DiscoverySettingsState): DiscoverySettingsViewModel
     }
 
-    companion object : MavericksViewModelFactory<DiscoverySettingsViewModel, DiscoverySettingsState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: DiscoverySettingsState): DiscoverySettingsViewModel? {
-            val fragment: DiscoverySettingsFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<DiscoverySettingsViewModel, DiscoverySettingsState> by hiltMavericksViewModelFactory()
 
     private val identityService = session.identityService()
     private val termsService: TermsService = session
diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt
index dd4db36387..fcea2e92b1 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt
@@ -24,10 +24,10 @@ import android.view.inputmethod.EditorInfo
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.text.toSpannable
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.registerStartForActivityResult
@@ -37,11 +37,13 @@ import im.vector.app.core.resources.ColorProvider
 import im.vector.app.core.utils.colorizeMatchingText
 import im.vector.app.databinding.FragmentSetIdentityServerBinding
 import im.vector.app.features.discovery.DiscoverySharedViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.terms.TermsService
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class SetIdentityServerFragment @Inject constructor(
-        val viewModelFactory: SetIdentityServerViewModel.Factory,
         val colorProvider: ColorProvider
 ) : VectorBaseFragment<FragmentSetIdentityServerBinding>() {
 
@@ -91,11 +93,11 @@ class SetIdentityServerFragment @Inject constructor(
 
         views.identityServerSetDefaultAlternativeTextInput
                 .textChanges()
-                .subscribe {
+                .onEach {
                     views.identityServerSetDefaultAlternativeTil.error = null
                     views.identityServerSetDefaultAlternativeSubmit.isEnabled = it.isNotEmpty()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.identityServerSetDefaultSubmit.debouncedClicks {
             viewModel.handle(SetIdentityServerAction.UseDefaultIdentityServer)
diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt
index 8921f0691d..c258652b49 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt
@@ -15,15 +15,16 @@
  */
 package im.vector.app.features.discovery.change
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import dagger.hilt.EntryPoints
 import im.vector.app.R
-import im.vector.app.core.di.HasScreenInjector
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.SingletonEntryPoint
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -42,26 +43,19 @@ class SetIdentityServerViewModel @AssistedInject constructor(
     VectorViewModel<SetIdentityServerState, SetIdentityServerAction, SetIdentityServerViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SetIdentityServerState): SetIdentityServerViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SetIdentityServerViewModel, SetIdentityServerState> {
+        override fun create(initialState: SetIdentityServerState): SetIdentityServerViewModel
     }
 
-    companion object : MavericksViewModelFactory<SetIdentityServerViewModel, SetIdentityServerState> {
-
-        override fun initialState(viewModelContext: ViewModelContext): SetIdentityServerState? {
-            val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
+    companion object : MavericksViewModelFactory<SetIdentityServerViewModel, SetIdentityServerState> by hiltMavericksViewModelFactory() {
 
+        override fun initialState(viewModelContext: ViewModelContext): SetIdentityServerState {
+            val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
             return SetIdentityServerState(
                     homeServerUrl = session.sessionParams.homeServerUrl,
                     defaultIdentityServerUrl = session.identityService().getDefaultIdentityServer()
             )
         }
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SetIdentityServerState): SetIdentityServerViewModel? {
-            val fragment: SetIdentityServerFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
     }
 
     var currentWantedUrl: String? = null
diff --git a/vector/src/main/java/im/vector/app/features/form/FormEditTextWithDeleteItem.kt b/vector/src/main/java/im/vector/app/features/form/FormEditTextWithDeleteItem.kt
new file mode 100644
index 0000000000..abcd1429d4
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/form/FormEditTextWithDeleteItem.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.form
+
+import android.text.Editable
+import android.view.inputmethod.EditorInfo
+import android.widget.ImageButton
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import com.google.android.material.textfield.TextInputEditText
+import com.google.android.material.textfield.TextInputLayout
+import im.vector.app.R
+import im.vector.app.core.epoxy.ClickListener
+import im.vector.app.core.epoxy.TextListener
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.core.epoxy.addTextChangedListenerOnce
+import im.vector.app.core.epoxy.onClick
+import im.vector.app.core.extensions.setTextIfDifferent
+import im.vector.app.core.platform.SimpleTextWatcher
+
+@EpoxyModelClass(layout = R.layout.item_form_text_input_with_delete)
+abstract class FormEditTextWithDeleteItem : VectorEpoxyModel<FormEditTextWithDeleteItem.Holder>() {
+
+    @EpoxyAttribute
+    var hint: String? = null
+
+    @EpoxyAttribute
+    var value: String? = null
+
+    @EpoxyAttribute
+    var enabled: Boolean = true
+
+    @EpoxyAttribute
+    var singleLine: Boolean = true
+
+    @EpoxyAttribute
+    var imeOptions: Int? = null
+
+    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
+    var onTextChange: TextListener? = null
+
+    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
+    var onDeleteClicked: ClickListener? = null
+
+    private val onTextChangeListener = object : SimpleTextWatcher() {
+        override fun afterTextChanged(s: Editable) {
+            onTextChange?.invoke(s.toString())
+        }
+    }
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        holder.textInputLayout.isEnabled = enabled
+        holder.textInputLayout.hint = hint
+
+        holder.textInputEditText.setTextIfDifferent(value)
+
+        holder.textInputEditText.isEnabled = enabled
+        holder.textInputEditText.isSingleLine = singleLine
+
+        holder.textInputEditText.imeOptions =
+                imeOptions ?: when (singleLine) {
+                    true  -> EditorInfo.IME_ACTION_NEXT
+                    false -> EditorInfo.IME_ACTION_NONE
+                }
+
+        holder.textInputEditText.addTextChangedListenerOnce(onTextChangeListener)
+
+        holder.textInputDeleteButton.onClick(onDeleteClicked)
+    }
+
+    override fun shouldSaveViewState(): Boolean {
+        return false
+    }
+
+    override fun unbind(holder: Holder) {
+        super.unbind(holder)
+        holder.textInputEditText.removeTextChangedListener(onTextChangeListener)
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val textInputLayout by bind<TextInputLayout>(R.id.formTextInputTextInputLayout)
+        val textInputEditText by bind<TextInputEditText>(R.id.formTextInputTextInputEditText)
+        val textInputDeleteButton by bind<ImageButton>(R.id.formTextInputDeleteButton)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
index 3e01742794..e8798859b2 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt
@@ -34,10 +34,10 @@ import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.AppStateHandler
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.registerStartForActivityResult
@@ -74,8 +74,9 @@ import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet
 import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
 import im.vector.app.features.themes.ThemeUtils
 import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
-import im.vector.app.features.workers.signout.ServerBackupStatusViewState
 import im.vector.app.core.pushers.UPHelper
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.session.initsync.SyncStatusService
@@ -93,13 +94,10 @@ data class HomeActivityArgs(
         val inviteNotificationRoomId: String? = null
 ) : Parcelable
 
+@AndroidEntryPoint
 class HomeActivity :
         VectorBaseActivity<ActivityHomeBinding>(),
         ToolbarConfigurable,
-        UnknownDeviceDetectorSharedViewModel.Factory,
-        ServerBackupStatusViewModel.Factory,
-        UnreadMessagesSharedViewModel.Factory,
-        PromoteRestrictedViewModel.Factory,
         NavigationInterceptor,
         SpaceInviteBottomSheet.InteractionListener,
         MatrixToBottomSheet.InteractionListener {
@@ -107,11 +105,8 @@ class HomeActivity :
     private lateinit var sharedActionViewModel: HomeSharedActionViewModel
 
     private val homeActivityViewModel: HomeActivityViewModel by viewModel()
-    @Inject lateinit var viewModelFactory: HomeActivityViewModel.Factory
 
     private val serverBackupStatusViewModel: ServerBackupStatusViewModel by viewModel()
-    @Inject lateinit var serverBackupviewModelFactory: ServerBackupStatusViewModel.Factory
-    @Inject lateinit var promoteRestrictedViewModelFactory: PromoteRestrictedViewModel.Factory
     private val promoteRestrictedViewModel: PromoteRestrictedViewModel by viewModel()
 
     @Inject lateinit var activeSessionHolder: ActiveSessionHolder
@@ -121,8 +116,6 @@ class HomeActivity :
     @Inject lateinit var vectorPreferences: VectorPreferences
     @Inject lateinit var popupAlertManager: PopupAlertManager
     @Inject lateinit var shortcutsHandler: ShortcutsHandler
-    @Inject lateinit var unknownDeviceViewModelFactory: UnknownDeviceDetectorSharedViewModel.Factory
-    @Inject lateinit var unreadMessagesSharedViewModelFactory: UnreadMessagesSharedViewModel.Factory
     @Inject lateinit var permalinkHandler: PermalinkHandler
     @Inject lateinit var avatarRenderer: AvatarRenderer
     @Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter
@@ -177,22 +170,6 @@ class HomeActivity :
 
     override fun getBinding() = ActivityHomeBinding.inflate(layoutInflater)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
-    override fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel {
-        return unknownDeviceViewModelFactory.create(initialState)
-    }
-
-    override fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel {
-        return serverBackupviewModelFactory.create(initialState)
-    }
-
-    override fun create(initialState: UnreadMessagesState): UnreadMessagesSharedViewModel {
-        return unreadMessagesSharedViewModelFactory.create(initialState)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
@@ -205,8 +182,8 @@ class HomeActivity :
         }
 
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         is HomeActivitySharedAction.OpenDrawer        -> views.drawerLayout.openDrawer(GravityCompat.START)
                         is HomeActivitySharedAction.CloseDrawer       -> views.drawerLayout.closeDrawer(GravityCompat.START)
@@ -249,7 +226,7 @@ class HomeActivity :
                         }
                     }.exhaustive
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
 
         val args = intent.getParcelableExtra<HomeActivityArgs>(Mavericks.KEY_ARG)
 
@@ -270,13 +247,12 @@ class HomeActivity :
                 is HomeActivityViewEvents.OnCrossSignedInvalidated      -> handleCrossSigningInvalidated(it)
             }.exhaustive
         }
-        homeActivityViewModel.subscribe(this) { renderState(it) }
+        homeActivityViewModel.onEach { renderState(it) }
 
-        shortcutsHandler.observeRoomsAndBuildShortcuts()
-                .disposeOnDestroy()
+        shortcutsHandler.observeRoomsAndBuildShortcuts(lifecycleScope)
 
         if (!vectorPreferences.didPromoteNewRestrictedFeature()) {
-            promoteRestrictedViewModel.subscribe(this) {
+            promoteRestrictedViewModel.onEach {
                 if (it.activeSpaceSummary != null && !it.activeSpaceSummary.isPublic &&
                         it.activeSpaceSummary.otherMemberIds.isNotEmpty()) {
                     // It's a private space with some members show this once
@@ -300,14 +276,13 @@ class HomeActivity :
             val resolvedLink = when {
                 // Element custom scheme is not handled by the sdk, convert it to matrix.to link for compatibility
                 deepLink.startsWith(MATRIX_TO_CUSTOM_SCHEME_URL_BASE) -> {
-                    val let = when {
+                    when {
                         deepLink.startsWith(USER_LINK_PREFIX) -> deepLink.substring(USER_LINK_PREFIX.length)
                         deepLink.startsWith(ROOM_LINK_PREFIX) -> deepLink.substring(ROOM_LINK_PREFIX.length)
                         else                                  -> null
                     }?.let { permalinkId ->
                         activeSessionHolder.getSafeActiveSession()?.permalinkService()?.createPermalink(permalinkId)
                     }
-                    let
                 }
                 else                                                  -> deepLink
             }
@@ -594,8 +569,6 @@ class HomeActivity :
         }
     }
 
-    override fun create(initialState: ActiveSpaceViewState) = promoteRestrictedViewModelFactory.create(initialState)
-
     override fun mxToBottomSheetNavigateToRoom(roomId: String) {
         navigator.openRoom(this, roomId)
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
index 627ff4be12..59b9cafd6e 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
@@ -17,14 +17,13 @@
 package im.vector.app.features.home
 
 import androidx.lifecycle.asFlow
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.login.ReAuthHelper
@@ -58,26 +57,17 @@ import kotlin.coroutines.resumeWithException
 
 class HomeActivityViewModel @AssistedInject constructor(
         @Assisted initialState: HomeActivityViewState,
-        @Assisted private val args: HomeActivityArgs,
         private val activeSessionHolder: ActiveSessionHolder,
         private val reAuthHelper: ReAuthHelper,
         private val vectorPreferences: VectorPreferences
 ) : VectorViewModel<HomeActivityViewState, HomeActivityViewActions, HomeActivityViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: HomeActivityViewState, args: HomeActivityArgs): HomeActivityViewModel
+    interface Factory : MavericksAssistedViewModelFactory<HomeActivityViewModel, HomeActivityViewState> {
+        override fun create(initialState: HomeActivityViewState): HomeActivityViewModel
     }
 
-    companion object : MavericksViewModelFactory<HomeActivityViewModel, HomeActivityViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: HomeActivityViewState): HomeActivityViewModel? {
-            val activity: HomeActivity = viewModelContext.activity()
-            val args: HomeActivityArgs? = activity.intent.getParcelableExtra(Mavericks.KEY_ARG)
-            return activity.viewModelFactory.create(state, args ?: HomeActivityArgs(clearNotification = false, accountCreation = false))
-        }
-    }
+    companion object : MavericksViewModelFactory<HomeActivityViewModel, HomeActivityViewState> by hiltMavericksViewModelFactory()
 
     private var checkBootstrap = false
     private var onceTrusted = false
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
index 62318d140f..ec16ab85c6 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt
@@ -57,15 +57,12 @@ import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DI
 import im.vector.app.features.themes.ThemeUtils
 import im.vector.app.features.workers.signout.BannerState
 import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
-import im.vector.app.features.workers.signout.ServerBackupStatusViewState
 import org.matrix.android.sdk.api.session.group.model.GroupSummary
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
 import javax.inject.Inject
 
 class HomeDetailFragment @Inject constructor(
-        val homeDetailViewModelFactory: HomeDetailViewModel.Factory,
-        private val serverBackupStatusViewModelFactory: ServerBackupStatusViewModel.Factory,
         private val avatarRenderer: AvatarRenderer,
         private val colorProvider: ColorProvider,
         private val alertManager: PopupAlertManager,
@@ -74,8 +71,7 @@ class HomeDetailFragment @Inject constructor(
         private val appStateHandler: AppStateHandler
 ) : VectorBaseFragment<FragmentHomeDetailBinding>(),
         KeysBackupBanner.Delegate,
-        CurrentCallsView.Callback,
-        ServerBackupStatusViewModel.Factory {
+        CurrentCallsView.Callback {
 
     private val viewModel: HomeDetailViewModel by fragmentViewModel()
     private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
@@ -368,7 +364,7 @@ class HomeDetailFragment @Inject constructor(
 
     private fun setupKeysBackupBanner() {
         serverBackupStatusViewModel
-                .subscribe(this) {
+                .onEach {
                     when (val banState = it.bannerState.invoke()) {
                         is BannerState.Setup  -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
                         BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
@@ -580,8 +576,4 @@ class HomeDetailFragment @Inject constructor(
         }
         return this
     }
-
-    override fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel {
-        return serverBackupStatusViewModelFactory.create(initialState)
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
index d981a29fec..1c1d012cc8 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
@@ -17,7 +17,6 @@
 package im.vector.app.features.home
 
 import androidx.lifecycle.asFlow
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
@@ -25,7 +24,10 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
 import im.vector.app.RoomGroupingMethod
-import im.vector.app.core.di.HasScreenInjector
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.extensions.singletonEntryPoint
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.call.dialpad.DialPadLookup
 import im.vector.app.features.call.lookup.CallProtocolsChecker
@@ -35,10 +37,13 @@ import im.vector.app.features.invite.AutoAcceptInvites
 import im.vector.app.features.invite.showInvites
 import im.vector.app.features.settings.VectorDataStore
 import im.vector.app.features.ui.UiStateRepository
-import io.reactivex.schedulers.Schedulers
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.query.ActiveSpaceFilter
 import org.matrix.android.sdk.api.query.RoomCategoryFilter
@@ -49,9 +54,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import org.matrix.android.sdk.api.util.toMatrixItem
 import org.matrix.android.sdk.flow.flow
-import org.matrix.android.sdk.rx.asObservable
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
 
 /**
  * View model used to update the home bottom bar notification counts, observe the sync state and
@@ -65,28 +68,22 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
                                                       private val directRoomHelper: DirectRoomHelper,
                                                       private val appStateHandler: AppStateHandler,
                                                       private val autoAcceptInvites: AutoAcceptInvites) :
-    VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
+        VectorViewModel<HomeDetailViewState, HomeDetailAction, HomeDetailViewEvents>(initialState),
         CallProtocolsChecker.Listener {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: HomeDetailViewState): HomeDetailViewModel
+    interface Factory : MavericksAssistedViewModelFactory<HomeDetailViewModel, HomeDetailViewState> {
+        override fun create(initialState: HomeDetailViewState): HomeDetailViewModel
     }
 
-    companion object : MavericksViewModelFactory<HomeDetailViewModel, HomeDetailViewState> {
+    companion object : MavericksViewModelFactory<HomeDetailViewModel, HomeDetailViewState> by hiltMavericksViewModelFactory() {
 
-        override fun initialState(viewModelContext: ViewModelContext): HomeDetailViewState? {
-            val uiStateRepository = (viewModelContext.activity as HasScreenInjector).injector().uiStateRepository()
+        override fun initialState(viewModelContext: ViewModelContext): HomeDetailViewState {
+            val uiStateRepository = viewModelContext.activity.singletonEntryPoint().uiStateRepository()
             return HomeDetailViewState(
                     currentTab = HomeTab.RoomList(uiStateRepository.getDisplayMode())
             )
         }
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: HomeDetailViewState): HomeDetailViewModel? {
-            val fragment: HomeDetailFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.homeDetailViewModelFactory.create(state)
-        }
     }
 
     init {
@@ -199,18 +196,15 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
 
     private fun observeRoomGroupingMethod() {
         appStateHandler.selectedRoomGroupingObservable
-                .subscribe {
-                    setState {
-                        copy(
-                                roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
-                        )
-                    }
+                .setOnEach {
+                    copy(
+                            roomGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
+                    )
                 }
-                .disposeOnClear()
     }
 
     private fun observeRoomSummaries() {
-        appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged().switchMap {
+        appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged().flatMapLatest {
             // we use it as a trigger to all changes in room, but do not really load
             // the actual models
             session.getPagedRoomSummariesLive(
@@ -218,11 +212,10 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
                         memberships = Membership.activeMemberships()
                     },
                     sortOrder = RoomSortOrder.NONE
-            ).asObservable()
+            ).asFlow()
         }
-                .observeOn(Schedulers.computation())
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .subscribe {
+                .throttleFirst(300)
+                .onEach {
                     when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
                         is RoomGroupingMethod.ByLegacyGroup -> {
                             // TODO!!
@@ -279,6 +272,6 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
                         }
                     }
                 }
-                .disposeOnClear()
+                .launchIn(viewModelScope)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeModule.kt b/vector/src/main/java/im/vector/app/features/home/HomeModule.kt
index 5c34d0715d..0782bbb573 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeModule.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeModule.kt
@@ -19,9 +19,11 @@ package im.vector.app.features.home
 import android.os.Handler
 import dagger.Module
 import dagger.Provides
+import dagger.hilt.migration.DisableInstallInCheck
 import im.vector.app.features.home.room.detail.timeline.TimelineEventControllerHandler
 import im.vector.app.features.home.room.detail.timeline.helper.TimelineAsyncHelper
 
+@DisableInstallInCheck
 @Module
 object HomeModule {
 
diff --git a/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt
index 0c8c9e480c..77ee23f732 100644
--- a/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt
@@ -16,20 +16,20 @@
 
 package im.vector.app.features.home
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
 import im.vector.app.RoomGroupingMethod
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
+import kotlinx.coroutines.flow.distinctUntilChanged
 import org.matrix.android.sdk.api.query.QueryStringValue
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toModel
@@ -72,21 +72,11 @@ class PromoteRestrictedViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ActiveSpaceViewState): PromoteRestrictedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<PromoteRestrictedViewModel, ActiveSpaceViewState> {
+        override fun create(initialState: ActiveSpaceViewState): PromoteRestrictedViewModel
     }
 
-    companion object : MavericksViewModelFactory<PromoteRestrictedViewModel, ActiveSpaceViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: ActiveSpaceViewState): PromoteRestrictedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<PromoteRestrictedViewModel, ActiveSpaceViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: EmptyAction) {}
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt b/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt
index 7514d455aa..7622c8b5de 100644
--- a/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt
+++ b/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt
@@ -21,52 +21,104 @@ import android.content.pm.ShortcutManager
 import android.os.Build
 import androidx.core.content.getSystemService
 import androidx.core.content.pm.ShortcutManagerCompat
+import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import io.reactivex.disposables.Disposable
-import io.reactivex.disposables.Disposables
+import im.vector.app.core.dispatchers.CoroutineDispatchers
+import im.vector.app.core.resources.StringProvider
+import im.vector.app.features.pin.PinCodeStore
+import im.vector.app.features.pin.PinCodeStoreListener
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onCompletion
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
 import org.matrix.android.sdk.api.session.room.RoomSortOrder
 import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
-import org.matrix.android.sdk.rx.asObservable
+import org.matrix.android.sdk.flow.flow
+import timber.log.Timber
+import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
 
 class ShortcutsHandler @Inject constructor(
         private val context: Context,
+        private val stringProvider: StringProvider,
+        private val appDispatchers: CoroutineDispatchers,
         private val shortcutCreator: ShortcutCreator,
-        private val activeSessionHolder: ActiveSessionHolder
-) {
+        private val activeSessionHolder: ActiveSessionHolder,
+        private val pinCodeStore: PinCodeStore
+) : PinCodeStoreListener {
 
-    fun observeRoomsAndBuildShortcuts(): Disposable {
+    private val isRequestPinShortcutSupported = ShortcutManagerCompat.isRequestPinShortcutSupported(context)
+    private val maxShortcutCountPerActivity = ShortcutManagerCompat.getMaxShortcutCountPerActivity(context)
+
+    // Value will be set correctly if necessary
+    private var hasPinCode = AtomicBoolean(true)
+
+    fun observeRoomsAndBuildShortcuts(coroutineScope: CoroutineScope): Job {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
             // No op
-            return Disposables.empty()
+            return Job()
         }
-
-        return activeSessionHolder.getSafeActiveSession()
-                ?.getPagedRoomSummariesLive(
-                        roomSummaryQueryParams {
-                            memberships = listOf(Membership.JOIN)
-                        },
-                        sortOrder = RoomSortOrder.PRIORITY_AND_ACTIVITY
-                )
-                ?.asObservable()
-                ?.subscribe { rooms ->
+        hasPinCode.set(pinCodeStore.getEncodedPin() != null)
+        val session = activeSessionHolder.getSafeActiveSession() ?: return Job()
+        return session.flow().liveRoomSummaries(
+                roomSummaryQueryParams {
+                    memberships = listOf(Membership.JOIN)
+                },
+                sortOrder = RoomSortOrder.PRIORITY_AND_ACTIVITY
+        )
+                .onStart { pinCodeStore.addListener(this@ShortcutsHandler) }
+                .onCompletion { pinCodeStore.removeListener(this@ShortcutsHandler) }
+                .onEach { rooms ->
                     // Remove dead shortcuts (i.e. deleted rooms)
-                    val roomIds = rooms.map { it.roomId }
-                    val deadShortcutIds = ShortcutManagerCompat.getShortcuts(context, ShortcutManagerCompat.FLAG_MATCH_DYNAMIC)
-                            .map { it.id }
-                            .filter { !roomIds.contains(it) }
-                    ShortcutManagerCompat.removeLongLivedShortcuts(context, deadShortcutIds)
+                    removeDeadShortcuts(rooms.map { it.roomId })
 
-                    val shortcuts = rooms.mapIndexed { index, room ->
+                    // Create shortcuts
+                    createShortcuts(rooms)
+                }
+                .flowOn(appDispatchers.computation)
+                .launchIn(coroutineScope)
+    }
+
+    private fun removeDeadShortcuts(roomIds: List<String>) {
+        val deadShortcutIds = ShortcutManagerCompat.getShortcuts(context, ShortcutManagerCompat.FLAG_MATCH_DYNAMIC)
+                .map { it.id }
+                .filter { !roomIds.contains(it) }
+
+        if (deadShortcutIds.isNotEmpty()) {
+            Timber.d("Removing shortcut(s) $deadShortcutIds")
+            ShortcutManagerCompat.removeLongLivedShortcuts(context, deadShortcutIds)
+            if (isRequestPinShortcutSupported) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
+                    ShortcutManagerCompat.disableShortcuts(
+                            context,
+                            deadShortcutIds,
+                            stringProvider.getString(R.string.shortcut_disabled_reason_room_left)
+                    )
+                }
+            }
+        }
+    }
+
+    private fun createShortcuts(rooms: List<RoomSummary>) {
+        if (hasPinCode.get()) {
+            // No shortcut in this case (privacy)
+            ShortcutManagerCompat.removeAllDynamicShortcuts(context)
+        } else {
+            val shortcuts = rooms
+                    .take(maxShortcutCountPerActivity)
+                    .mapIndexed { index, room ->
                         shortcutCreator.create(room, index)
                     }
 
-                    shortcuts.forEach { shortcut ->
-                        ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
-                    }
-                }
-                ?: Disposables.empty()
+            shortcuts.forEach { shortcut ->
+                ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
+            }
+        }
     }
 
     fun clearShortcuts() {
@@ -82,13 +134,30 @@ class ShortcutsHandler @Inject constructor(
         ShortcutManagerCompat.removeLongLivedShortcuts(context, shortcuts)
 
         // We can only disabled pinned shortcuts with the API, but at least it will prevent the crash
-        if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)) {
+        if (isRequestPinShortcutSupported) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
                 context.getSystemService<ShortcutManager>()
-                        ?.let {
-                            it.disableShortcuts(it.pinnedShortcuts.map { pinnedShortcut -> pinnedShortcut.id })
+                        ?.pinnedShortcuts
+                        ?.takeIf { it.isNotEmpty() }
+                        ?.map { pinnedShortcut -> pinnedShortcut.id }
+                        ?.let { shortcutIdsToDisable ->
+                            ShortcutManagerCompat.disableShortcuts(
+                                    context,
+                                    shortcutIdsToDisable,
+                                    stringProvider.getString(R.string.shortcut_disabled_reason_sign_out)
+                            )
                         }
             }
         }
     }
+
+    override fun onPinSetUpChange(isConfigured: Boolean) {
+        hasPinCode.set(isConfigured)
+        if (isConfigured) {
+            // Remove shortcuts immediately
+            ShortcutManagerCompat.removeAllDynamicShortcuts(context)
+        }
+        // Else shortcut will be created next time any room summary is updated, or
+        // next time the app is started which is acceptable
+    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt
index 36e31770a9..8a36a4c19e 100644
--- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt
@@ -16,17 +16,16 @@
 
 package im.vector.app.features.home
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.platform.VectorViewModelAction
@@ -66,21 +65,11 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> {
+        override fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel
     }
 
-    companion object : MavericksViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<UnknownDeviceDetectorSharedViewModel, UnknownDevicesState> by hiltMavericksViewModelFactory()
 
     private val ignoredDeviceList = ArrayList<String>()
 
diff --git a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt
index d0df5304b6..dfc0a540ae 100644
--- a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt
@@ -16,23 +16,27 @@
 
 package im.vector.app.features.home
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
+import androidx.lifecycle.asFlow
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
 import im.vector.app.RoomGroupingMethod
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.invite.AutoAcceptInvites
 import im.vector.app.features.settings.VectorPreferences
-import io.reactivex.Observable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
 import org.matrix.android.sdk.api.query.ActiveSpaceFilter
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.room.RoomSortOrder
@@ -40,8 +44,6 @@ import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.spaceSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
-import org.matrix.android.sdk.rx.asObservable
-import java.util.concurrent.TimeUnit
 
 data class UnreadMessagesState(
         val homeSpaceUnread: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0, 0),
@@ -58,24 +60,14 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
                                                                 private val vectorPreferences: VectorPreferences,
                                                                 appStateHandler: AppStateHandler,
                                                                 private val autoAcceptInvites: AutoAcceptInvites) :
-    VectorViewModel<UnreadMessagesState, EmptyAction, EmptyViewEvents>(initialState) {
+        VectorViewModel<UnreadMessagesState, EmptyAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: UnreadMessagesState): UnreadMessagesSharedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<UnreadMessagesSharedViewModel, UnreadMessagesState> {
+        override fun create(initialState: UnreadMessagesState): UnreadMessagesSharedViewModel
     }
 
-    companion object : MavericksViewModelFactory<UnreadMessagesSharedViewModel, UnreadMessagesState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: UnreadMessagesState): UnreadMessagesSharedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<UnreadMessagesSharedViewModel, UnreadMessagesState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: EmptyAction) {}
 
@@ -86,8 +78,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
                     this.memberships = listOf(Membership.JOIN)
                     this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
                 }, sortOrder = RoomSortOrder.NONE
-        ).asObservable()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
+        ).asFlow()
+                .throttleFirst(300)
                 .execute {
                     val counts = session.getNotificationCountForRooms(
                             roomSummaryQueryParams {
@@ -115,124 +107,122 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
                     )
                 }
 
-        Observable.combineLatest(
+        combine(
                 appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged(),
-                appStateHandler.selectedRoomGroupingObservable.switchMap {
+                appStateHandler.selectedRoomGroupingObservable.flatMapLatest {
                     session.getPagedRoomSummariesLive(
                             roomSummaryQueryParams {
                                 this.memberships = Membership.activeMemberships()
                             }, sortOrder = RoomSortOrder.NONE
-                    ).asObservable()
-                            .throttleFirst(300, TimeUnit.MILLISECONDS)
-                            .observeOn(Schedulers.computation())
-                },
-                { groupingMethod, _ ->
-                    when (groupingMethod.orNull()) {
-                        is RoomGroupingMethod.ByLegacyGroup -> {
-                            // currently not supported
-                            CountInfo(
-                                    RoomAggregateNotificationCount(0, 0, 0),
-                                    RoomAggregateNotificationCount(0, 0, 0)
-                            )
-                        }
-                        is RoomGroupingMethod.BySpace       -> {
-                            //val selectedSpace = appStateHandler.safeActiveSpaceId()
-
-                            val inviteCount = if (autoAcceptInvites.hideInvites) {
-                                0
-                            } else {
-                                session.getRoomSummaries(
-                                        roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
-                                ).size
-                            }
-
-                            val spacesShowAllRoomsInHome = vectorPreferences.prefSpacesShowAllRoomInHome()
-
-                            val spaceInviteCount = if (autoAcceptInvites.hideInvites) {
-                                0
-                            } else {
-                                session.getRoomSummaries(
-                                        spaceSummaryQueryParams {
-                                            this.memberships = listOf(Membership.INVITE)
-                                        }
-                                ).size
-                            }
-
-                            val totalCount = session.getNotificationCountForRooms(
-                                    roomSummaryQueryParams {
-                                        this.memberships = listOf(Membership.JOIN)
-                                        this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
-                                            !spacesShowAllRoomsInHome
-                                        } ?: ActiveSpaceFilter.None
-                                    }
-                            )
-
-                            val counts = RoomAggregateNotificationCount(
-                                    totalCount.notificationCount + inviteCount,
-                                    totalCount.highlightCount + inviteCount,
-                                    totalCount.unreadCount
-                            )
-
-                            // SC: count total room notifications for drawer badge, instead of filtering for others like Element does,
-                            // to prevent counting rooms multiple times
-                            val topLevelTotalCount = if (spacesShowAllRoomsInHome) {
-                                totalCount
-                            } else {
-                                session.getNotificationCountForRooms(
-                                        roomSummaryQueryParams {
-                                            this.memberships = listOf(Membership.JOIN)
-                                            this.activeSpaceFilter = ActiveSpaceFilter.None
-                                        }
-                                )
-                            }
-
-                            val topLevelCounts = RoomAggregateNotificationCount(
-                                    topLevelTotalCount.notificationCount + inviteCount + spaceInviteCount,
-                                    topLevelTotalCount.highlightCount + inviteCount + spaceInviteCount,
-                                    topLevelTotalCount.unreadCount
-                            )
-
-                            CountInfo(homeCount = counts, otherCount = topLevelCounts)
-
-                            /*
-                            val rootCounts = session.spaceService().getRootSpaceSummaries()
-                                    .filter {
-                                        // filter out current selection
-                                        it.roomId != selectedSpace
-                                    }
-
-                            CountInfo(
-                                    homeCount = counts,
-                                    otherCount = RoomAggregateNotificationCount(
-                                            notificationCount = rootCounts.fold(0, { acc, rs -> acc + rs.notificationCount }) +
-                                                    (counts.notificationCount.takeIf { selectedSpace != null } ?: 0) +
-                                                    spaceInviteCount,
-                                            highlightCount = rootCounts.fold(0, { acc, rs -> acc + rs.highlightCount }) +
-                                                    (counts.highlightCount.takeIf { selectedSpace != null } ?: 0) +
-                                                    spaceInviteCount,
-
-                                            unreadCount = rootCounts.fold(0, { acc, rs -> acc + (if (rs.scIsUnread()) 1 else 0) }) +
-                                                    (counts.unreadCount.takeIf { selectedSpace != null } ?: 0) +
-                                                    spaceInviteCount,
-                                            markedUnreadCount = rootCounts.fold(0, { acc, rs -> acc + (if (rs.markedUnread) 1 else 0) }) +
-                                                    (counts.markedUnreadCount.takeIf { selectedSpace != null } ?: 0)
-                                    )
-                            )
-                             */
-                        }
-                        null                                -> {
-                            CountInfo(
-                                    RoomAggregateNotificationCount(0, 0, 0),
-                                    RoomAggregateNotificationCount(0, 0, 0)
-                            )
-                        }
-                    }
+                    ).asFlow()
+                            .throttleFirst(300)
                 }
-        ).execute {
-            copy(
-                    homeSpaceUnread = it.invoke()?.homeCount ?: RoomAggregateNotificationCount(0, 0, 0),
-                    otherSpacesUnread = it.invoke()?.otherCount ?: RoomAggregateNotificationCount(0, 0, 0)
-            )
+        ) { groupingMethod, _ ->
+            when (groupingMethod.orNull()) {
+                is RoomGroupingMethod.ByLegacyGroup -> {
+                    // currently not supported
+                    CountInfo(
+                            RoomAggregateNotificationCount(0, 0, 0),
+                            RoomAggregateNotificationCount(0, 0, 0)
+                    )
+                }
+                is RoomGroupingMethod.BySpace       -> {
+                    //val selectedSpace = appStateHandler.safeActiveSpaceId()
+
+                    val inviteCount = if (autoAcceptInvites.hideInvites) {
+                        0
+                    } else {
+                        session.getRoomSummaries(
+                                roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
+                        ).size
+                    }
+
+                    val spacesShowAllRoomsInHome = vectorPreferences.prefSpacesShowAllRoomInHome()
+
+                    val spaceInviteCount = if (autoAcceptInvites.hideInvites) {
+                        0
+                    } else {
+                        session.getRoomSummaries(
+                                spaceSummaryQueryParams {
+                                    this.memberships = listOf(Membership.INVITE)
+                                }
+                        ).size
+                    }
+
+                    val totalCount = session.getNotificationCountForRooms(
+                            roomSummaryQueryParams {
+                                this.memberships = listOf(Membership.JOIN)
+                                this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null).takeIf {
+                                    !spacesShowAllRoomsInHome
+                                } ?: ActiveSpaceFilter.None
+                            }
+                    )
+
+                    val counts = RoomAggregateNotificationCount(
+                            totalCount.notificationCount + inviteCount,
+                            totalCount.highlightCount + inviteCount,
+                            totalCount.unreadCount
+                    )
+
+                    // SC: count total room notifications for drawer badge, instead of filtering for others like Element does,
+                    // to prevent counting rooms multiple times
+                    val topLevelTotalCount = if (spacesShowAllRoomsInHome) {
+                        totalCount
+                    } else {
+                        session.getNotificationCountForRooms(
+                                roomSummaryQueryParams {
+                                    this.memberships = listOf(Membership.JOIN)
+                                    this.activeSpaceFilter = ActiveSpaceFilter.None
+                                }
+                        )
+                    }
+
+                    val topLevelCounts = RoomAggregateNotificationCount(
+                            topLevelTotalCount.notificationCount + inviteCount + spaceInviteCount,
+                            topLevelTotalCount.highlightCount + inviteCount + spaceInviteCount,
+                            topLevelTotalCount.unreadCount
+                    )
+
+                    CountInfo(homeCount = counts, otherCount = topLevelCounts)
+
+                    /*
+                    val rootCounts = session.spaceService().getRootSpaceSummaries()
+                            .filter {
+                                // filter out current selection
+                                it.roomId != selectedSpace
+                            }
+
+                    CountInfo(
+                            homeCount = counts,
+                            otherCount = RoomAggregateNotificationCount(
+                                    notificationCount = rootCounts.fold(0, { acc, rs -> acc + rs.notificationCount }) +
+                                            (counts.notificationCount.takeIf { selectedSpace != null } ?: 0) +
+                                            spaceInviteCount,
+                                    highlightCount = rootCounts.fold(0, { acc, rs -> acc + rs.highlightCount }) +
+                                            (counts.highlightCount.takeIf { selectedSpace != null } ?: 0) +
+                                            spaceInviteCount,
+
+                                    unreadCount = rootCounts.fold(0, { acc, rs -> acc + (if (rs.scIsUnread()) 1 else 0) }) +
+                                            (counts.unreadCount.takeIf { selectedSpace != null } ?: 0) +
+                                            spaceInviteCount
+                            )
+                    )
+                     */
+                }
+                null                                -> {
+                    CountInfo(
+                            RoomAggregateNotificationCount(0, 0, 0),
+                            RoomAggregateNotificationCount(0, 0, 0)
+                    )
+                }
+            }
         }
+                .flowOn(Dispatchers.Default)
+                .execute {
+                    copy(
+                            homeSpaceUnread = it.invoke()?.homeCount ?: RoomAggregateNotificationCount(0, 0, 0),
+                            otherSpacesUnread = it.invoke()?.otherCount ?: RoomAggregateNotificationCount(0, 0, 0)
+                    )
+                }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
index 47a8256628..4d44ff775a 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsFragment.kt
@@ -31,8 +31,7 @@ import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
 import javax.inject.Inject
 
 class BreadcrumbsFragment @Inject constructor(
-        private val breadcrumbsController: BreadcrumbsController,
-        val breadcrumbsViewModelFactory: BreadcrumbsViewModel.Factory
+        private val breadcrumbsController: BreadcrumbsController
 ) : VectorBaseFragment<FragmentBreadcrumbsBinding>(),
         BreadcrumbsController.Listener {
 
diff --git a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt
index 8ed44053a1..112b7e8574 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt
@@ -16,12 +16,12 @@
 
 package im.vector.app.features.home.room.breadcrumbs
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -33,21 +33,14 @@ import org.matrix.android.sdk.flow.flow
 
 class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: BreadcrumbsViewState,
                                                        private val session: Session) :
-    VectorViewModel<BreadcrumbsViewState, EmptyAction, EmptyViewEvents>(initialState) {
+        VectorViewModel<BreadcrumbsViewState, EmptyAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: BreadcrumbsViewState): BreadcrumbsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<BreadcrumbsViewModel, BreadcrumbsViewState> {
+        override fun create(initialState: BreadcrumbsViewState): BreadcrumbsViewModel
     }
 
-    companion object : MavericksViewModelFactory<BreadcrumbsViewModel, BreadcrumbsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: BreadcrumbsViewState): BreadcrumbsViewModel? {
-            val fragment: BreadcrumbsFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.breadcrumbsViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<BreadcrumbsViewModel, BreadcrumbsViewState> by hiltMavericksViewModelFactory()
 
     init {
         observeBreadcrumbs()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt
index 7159f7b33a..ba559677c9 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt
@@ -25,8 +25,8 @@ import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.parentFragmentViewModel
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.epoxy.ClickListener
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.platform.ButtonStateView
@@ -34,6 +34,7 @@ import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetTombstoneJoinBinding
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class JoinReplacementRoomBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetTombstoneJoinBinding>() {
 
@@ -43,10 +44,6 @@ class JoinReplacementRoomBottomSheet :
     @Inject
     lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     private val viewModel: RoomDetailViewModel by parentFragmentViewModel()
 
     override val showExpanded: Boolean
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt
index 76c3816ce6..415ca7bc04 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt
@@ -24,10 +24,12 @@ import androidx.core.view.GravityCompat
 import androidx.drawerlayout.widget.DrawerLayout
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
+import androidx.lifecycle.lifecycleScope
+import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.platform.ToolbarConfigurable
@@ -39,16 +41,13 @@ import im.vector.app.features.navigation.Navigator
 import im.vector.app.features.room.RequireActiveMembershipAction
 import im.vector.app.features.room.RequireActiveMembershipViewEvents
 import im.vector.app.features.room.RequireActiveMembershipViewModel
-import im.vector.app.features.room.RequireActiveMembershipViewState
-import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewModel
-import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewState
-import javax.inject.Inject
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
+@AndroidEntryPoint
 class RoomDetailActivity :
         VectorBaseActivity<ActivityRoomDetailBinding>(),
         ToolbarConfigurable,
-        RequireActiveMembershipViewModel.Factory,
-        RoomWidgetPermissionViewModel.Factory,
         MatrixToBottomSheet.InteractionListener {
 
     override fun getBinding(): ActivityRoomDetailBinding {
@@ -77,24 +76,6 @@ class RoomDetailActivity :
     private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel
     private val requireActiveMembershipViewModel: RequireActiveMembershipViewModel by viewModel()
 
-    @Inject
-    lateinit var requireActiveMembershipViewModelFactory: RequireActiveMembershipViewModel.Factory
-
-    override fun create(initialState: RequireActiveMembershipViewState): RequireActiveMembershipViewModel {
-        // Due to shortcut, we cannot use MvRx args. Pass the first roomId here
-        return requireActiveMembershipViewModelFactory.create(initialState.copy(roomId = currentRoomId ?: ""))
-    }
-
-    @Inject
-    lateinit var permissionsViewModelFactory: RoomWidgetPermissionViewModel.Factory
-    override fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel {
-        return permissionsViewModelFactory.create(initialState)
-    }
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     // Simple filter
     var currentRoomId: String? = null
 
@@ -108,6 +89,7 @@ class RoomDetailActivity :
             intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
         }
         if (roomDetailArgs == null) return
+        intent.putExtra(Mavericks.KEY_ARG, roomDetailArgs)
         currentRoomId = roomDetailArgs.roomId
 
         if (isFirstCreation()) {
@@ -118,13 +100,13 @@ class RoomDetailActivity :
         sharedActionViewModel = viewModelProvider.get(RoomDetailSharedActionViewModel::class.java)
 
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         is RoomDetailSharedAction.SwitchToRoom -> switchToRoom(sharedAction)
                     }
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
 
         requireActiveMembershipViewModel.observeViewEvents {
             when (it) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
index c8a0090ec9..b403e2ee03 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
@@ -54,6 +54,7 @@ import androidx.core.view.forEach
 import androidx.core.view.isInvisible
 import androidx.core.view.isVisible
 import androidx.fragment.app.setFragmentResultListener
+import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.RecyclerView
@@ -67,8 +68,6 @@ import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.jakewharton.rxbinding3.view.focusChanges
-import com.jakewharton.rxbinding3.widget.textChanges
 import com.vanniktech.emoji.EmojiPopup
 import de.spiritcroc.recyclerview.widget.BetterLinearLayoutManager
 import im.vector.app.R
@@ -187,6 +186,10 @@ import im.vector.app.features.widgets.WidgetActivity
 import im.vector.app.features.widgets.WidgetArgs
 import im.vector.app.features.widgets.WidgetKind
 import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import kotlinx.parcelize.Parcelize
 import nl.dionsegijn.konfetti.models.Shape
@@ -218,10 +221,11 @@ import org.matrix.android.sdk.api.util.MimeTypes
 import org.matrix.android.sdk.api.util.toMatrixItem
 import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
 import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
+import reactivecircus.flowbinding.android.view.focusChanges
+import reactivecircus.flowbinding.android.widget.textChanges
 import timber.log.Timber
 import java.net.URL
 import java.util.UUID
-import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
 @Parcelize
@@ -241,7 +245,6 @@ class RoomDetailFragment @Inject constructor(
         private val permalinkHandler: PermalinkHandler,
         private val notificationDrawerManager: NotificationDrawerManager,
         val roomDetailViewModelFactory: RoomDetailViewModel.Factory,
-        val textComposerViewModelFactory: TextComposerViewModel.Factory,
         private val eventHtmlRenderer: EventHtmlRenderer,
         private val vectorPreferences: VectorPreferences,
         private val colorProvider: ColorProvider,
@@ -372,11 +375,11 @@ class RoomDetailFragment @Inject constructor(
         }
 
         sharedActionViewModel
-                .observe()
-                .subscribe {
+                .stream()
+                .onEach {
                     handleActions(it)
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         knownCallsViewModel
                 .liveKnownCalls
@@ -653,17 +656,27 @@ class RoomDetailFragment @Inject constructor(
                         setImageResource(R.drawable.ic_keyboard)
                     }
                 }
-                .setOnEmojiPopupDismissListener {
-                    if (isAdded) {
-                        views.composerLayout.views.composerEmojiButton.apply {
-                            contentDescription = getString(R.string.a11y_open_emoji_picker)
-                            setImageResource(R.drawable.ic_insert_emoji)
-                        }
+                .setOnEmojiPopupDismissListenerLifecycleAware {
+                    views.composerLayout.views.composerEmojiButton.apply {
+                        contentDescription = getString(R.string.a11y_open_emoji_picker)
+                        setImageResource(R.drawable.ic_insert_emoji)
                     }
                 }
                 .build(views.composerLayout.views.composerEditText)
     }
 
+    /**
+     *  Ensure dismiss actions only trigger when the fragment is in the started state
+     *  EmojiPopup by default dismisses onViewDetachedFromWindow, this can cause race conditions with onDestroyView
+     */
+    private fun EmojiPopup.Builder.setOnEmojiPopupDismissListenerLifecycleAware(action: () -> Unit): EmojiPopup.Builder {
+        return setOnEmojiPopupDismissListener {
+            if (lifecycle.currentState == Lifecycle.State.STARTED) {
+                action()
+            }
+        }
+    }
+
     private val permissionVoiceMessageLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
         if (allGranted) {
             // In this case, let the user start again the gesture
@@ -1402,24 +1415,23 @@ class RoomDetailFragment @Inject constructor(
     private fun observerUserTyping() {
         views.composerLayout.views.composerEditText.textChanges()
                 .skipInitialValue()
-                .debounce(300, TimeUnit.MILLISECONDS)
+                .debounce(300)
                 .map { it.isNotEmpty() }
-                .subscribe {
+                .onEach {
                     Timber.d("Typing: User is typing: $it")
                     textComposerViewModel.handle(TextComposerAction.UserIsTyping(it))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.composerLayout.views.composerEditText.focusChanges()
-                .subscribe {
+                .onEach {
                     if (it) {
                         // Prioritize staying scrolled at the bottom compared to keeping the unread messages line at the fixed position
                         setInitialForceScrollEnabled(false, stickToBottom = true)
                     }
-
                     roomDetailViewModel.handle(RoomDetailAction.ComposerFocusChange(it))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun sendUri(uri: Uri): Boolean {
@@ -2150,12 +2162,12 @@ class RoomDetailFragment @Inject constructor(
 // VectorInviteView.Callback
 
     override fun onAcceptInvite() {
-        notificationDrawerManager.clearMemberShipNotificationForRoom(roomDetailArgs.roomId)
+        notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(roomDetailArgs.roomId) }
         roomDetailViewModel.handle(RoomDetailAction.AcceptInvite)
     }
 
     override fun onRejectInvite() {
-        notificationDrawerManager.clearMemberShipNotificationForRoom(roomDetailArgs.roomId)
+        notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(roomDetailArgs.roomId) }
         roomDetailViewModel.handle(RoomDetailAction.RejectInvite)
     }
 
@@ -2206,6 +2218,7 @@ class RoomDetailFragment @Inject constructor(
             AttachmentTypeSelectorView.Type.AUDIO   -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
             AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
             AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment)
+            AttachmentTypeSelectorView.Type.POLL    -> navigator.openCreatePoll(requireContext(), roomDetailArgs.roomId)
         }.exhaustive
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
index f690cfdd68..359f57db3d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
@@ -27,16 +27,17 @@ import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.ViewModelContext
-import com.jakewharton.rxrelay2.BehaviorRelay
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.BuildConfig
 import im.vector.app.R
 import im.vector.app.core.extensions.exhaustive
+import im.vector.app.core.flow.chunk
 import im.vector.app.core.mvrx.runCatchingToAsync
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.utils.BehaviorDataSource
 import im.vector.app.features.attachments.toContentAttachmentData
 import im.vector.app.features.call.conference.ConferenceEvent
 import im.vector.app.features.call.conference.JitsiActiveConferenceHolder
@@ -56,14 +57,15 @@ import im.vector.app.features.session.coroutineScope
 import im.vector.app.features.settings.VectorDataStore
 import im.vector.app.features.settings.VectorPreferences
 import im.vector.app.features.voice.VoicePlayerHelper
-import io.reactivex.rxkotlin.subscribeBy
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.NonCancellable
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -99,7 +101,6 @@ import org.matrix.android.sdk.flow.flow
 import org.matrix.android.sdk.flow.unwrap
 import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
 import java.util.concurrent.atomic.AtomicBoolean
 
 class RoomDetailViewModel @AssistedInject constructor(
@@ -124,8 +125,8 @@ class RoomDetailViewModel @AssistedInject constructor(
 
     private val room = session.getRoom(initialState.roomId)!!
     private val eventId = initialState.eventId ?: if (loadRoomAtFirstUnread()) room.roomSummary()?.readMarkerId else null
-    private val invisibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsInvisible>()
-    private val visibleEventsObservable = BehaviorRelay.create<RoomDetailAction.TimelineEventTurnsVisible>()
+    private val invisibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsInvisible>()
+    private val visibleEventsSource = BehaviorDataSource<RoomDetailAction.TimelineEventTurnsVisible>()
     private var timelineEvents = MutableSharedFlow<List<TimelineEvent>>(0)
     val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId).apply {
         // Target the event just below $eventId in case that it is the readMarkerId
@@ -153,14 +154,16 @@ class RoomDetailViewModel @AssistedInject constructor(
         fun create(initialState: RoomDetailViewState): RoomDetailViewModel
     }
 
+    /**
+     * Can't use the hiltMaverick here because some dependencies are injected here and in fragment but they don't share the graph.
+     */
     companion object : MavericksViewModelFactory<RoomDetailViewModel, RoomDetailViewState> {
 
         const val PAGINATION_COUNT = 50
 
         @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
+        override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel {
             val fragment: RoomDetailFragment = (viewModelContext as FragmentViewModelContext).fragment()
-
             return fragment.roomDetailViewModelFactory.create(state)
         }
     }
@@ -575,7 +578,7 @@ class RoomDetailViewModel @AssistedInject constructor(
     }
 
     private fun handleEventInvisible(action: RoomDetailAction.TimelineEventTurnsInvisible) {
-        invisibleEventsObservable.accept(action)
+        invisibleEventsSource.post(action)
     }
 
     fun getMember(userId: String): RoomMemberSummary? {
@@ -727,12 +730,12 @@ class RoomDetailViewModel @AssistedInject constructor(
     private fun handleEventVisible(action: RoomDetailAction.TimelineEventTurnsVisible) {
         viewModelScope.launch(Dispatchers.Default) {
             if (action.event.root.sendState.isSent()) { // ignore pending/local events
-                visibleEventsObservable.accept(action)
+                visibleEventsSource.post(action)
             }
             // We need to update this with the related m.replace also (to move read receipt)
             action.event.annotations?.editSummary?.sourceEvents?.forEach {
                 room.getTimeLineEvent(it)?.let { event ->
-                    visibleEventsObservable.accept(RoomDetailAction.TimelineEventTurnsVisible(event))
+                    visibleEventsSource.post(RoomDetailAction.TimelineEventTurnsVisible(event))
                 }
             }
 
@@ -880,11 +883,13 @@ class RoomDetailViewModel @AssistedInject constructor(
     private fun observeEventDisplayedActions() {
         // We are buffering scroll events for half a second
         // and keep the most recent one to set the read receipt on.
-        visibleEventsObservable
-                .buffer(500, TimeUnit.MILLISECONDS)
+
+        visibleEventsSource
+                .stream()
+                .chunk(500)
                 .filter { it.isNotEmpty() }
-                .subscribeBy(onNext = { actions ->
-                    val bufferedMostRecentDisplayedEvent = actions.maxByOrNull { it.event.displayIndex }?.event ?: return@subscribeBy
+                .onEach { actions ->
+                    val bufferedMostRecentDisplayedEvent = actions.maxByOrNull { it.event.displayIndex }?.event ?: return@onEach
                     val globalMostRecentDisplayedEvent = mostRecentDisplayedEvent
                     if (trackUnreadMessages.get()) {
                         if (globalMostRecentDisplayedEvent == null) {
@@ -898,8 +903,9 @@ class RoomDetailViewModel @AssistedInject constructor(
                             tryOrNull { room.setReadReceipt(eventId) }
                         }
                     }
-                })
-                .disposeOnClear()
+                }
+                .flowOn(Dispatchers.Default)
+                .launchIn(viewModelScope)
     }
 
     private fun handleMarkAllAsRead() {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt
index 5ff3de8a4d..f42ce9f327 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt
@@ -17,14 +17,16 @@
 
 package im.vector.app.features.home.room.detail.composer
 
+import android.content.ClipData
 import android.content.Context
 import android.net.Uri
-import android.os.Build
 import android.text.Editable
 import android.util.AttributeSet
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.InputConnection
 import androidx.appcompat.widget.AppCompatEditText
+import androidx.core.view.OnReceiveContentListener
+import androidx.core.view.ViewCompat
 import androidx.core.view.inputmethod.EditorInfoCompat
 import androidx.core.view.inputmethod.InputConnectionCompat
 import im.vector.app.core.extensions.ooi
@@ -33,7 +35,7 @@ import im.vector.app.features.html.PillImageSpan
 import timber.log.Timber
 
 class ComposerEditText @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = android.R.attr.editTextStyle) :
-    AppCompatEditText(context, attrs, defStyleAttr) {
+        AppCompatEditText(context, attrs, defStyleAttr) {
 
     interface Callback {
         fun onRichContentSelected(contentUri: Uri): Boolean
@@ -43,23 +45,35 @@ class ComposerEditText @JvmOverloads constructor(context: Context, attrs: Attrib
     var callback: Callback? = null
 
     override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection? {
-        val ic = super.onCreateInputConnection(editorInfo) ?: return null
-        EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("*/*"))
+        var ic = super.onCreateInputConnection(editorInfo) ?: return null
+        val mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this) ?: arrayOf("image/*")
 
-        val callback =
-                InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, _ ->
-                    val lacksPermission = (flags and
-                            InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && lacksPermission) {
-                        try {
-                            inputContentInfo.requestPermission()
-                        } catch (e: Exception) {
-                            return@OnCommitContentListener false
-                        }
-                    }
-                    callback?.onRichContentSelected(inputContentInfo.contentUri) ?: false
+        EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes)
+        ic = InputConnectionCompat.createWrapper(this, ic, editorInfo)
+
+        val onReceiveContentListener = OnReceiveContentListener { _, payload ->
+            val split = payload.partition { item -> item.uri != null }
+            val uriContent = split.first
+            val remaining = split.second
+
+            if (uriContent != null) {
+                val clip: ClipData = uriContent.clip
+                for (i in 0 until clip.itemCount) {
+                    val uri = clip.getItemAt(i).uri
+                    // ... app-specific logic to handle the URI ...
+                    callback?.onRichContentSelected(uri)
                 }
-        return InputConnectionCompat.createWrapper(ic, editorInfo, callback)
+            }
+            // Return anything that we didn't handle ourselves. This preserves the default platform
+            // behavior for text and anything else for which we are not implementing custom handling.
+            // Return anything that we didn't handle ourselves. This preserves the default platform
+            // behavior for text and anything else for which we are not implementing custom handling.
+            remaining
+        }
+
+        ViewCompat.setOnReceiveContentListener(this, mimeTypes, onReceiveContentListener)
+
+        return ic
     }
 
     init {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt
index d369da6d86..8279d36cfd 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt
@@ -16,20 +16,19 @@
 
 package im.vector.app.features.home.room.detail.composer
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.command.CommandParser
 import im.vector.app.features.command.ParsedCommand
 import im.vector.app.features.home.room.detail.ChatEffect
-import im.vector.app.features.home.room.detail.RoomDetailFragment
 import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator
 import im.vector.app.features.home.room.detail.toMessageType
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
@@ -48,7 +47,6 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
 import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
 import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageType
-import org.matrix.android.sdk.api.session.room.model.message.OptionItem
 import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
 import org.matrix.android.sdk.api.session.room.send.UserDraft
 import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
@@ -105,7 +103,7 @@ class TextComposerViewModel @AssistedInject constructor(
     }
 
     private fun subscribeToStateInternal() {
-        selectSubscribe(TextComposerViewState::sendMode, TextComposerViewState::canSendMessage, TextComposerViewState::isVoiceRecording) { _, _, _ ->
+        onEach(TextComposerViewState::sendMode, TextComposerViewState::canSendMessage, TextComposerViewState::isVoiceRecording) { _, _, _ ->
             updateIsSendButtonVisibility(false)
         }
     }
@@ -126,7 +124,7 @@ class TextComposerViewModel @AssistedInject constructor(
 
     private fun handleEnterEditMode(action: TextComposerAction.EnterEditMode) {
         room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
-            setState { copy(sendMode = SendMode.EDIT(timelineEvent, timelineEvent.getTextEditableContent() ?: "")) }
+            setState { copy(sendMode = SendMode.EDIT(timelineEvent, timelineEvent.getTextEditableContent())) }
         }
     }
 
@@ -262,11 +260,6 @@ class TextComposerViewModel @AssistedInject constructor(
                             _viewEvents.post(TextComposerViewEvents.SlashCommandResultOk())
                             popDraft()
                         }
-                        is ParsedCommand.SendPoll                 -> {
-                            room.sendPoll(slashCommandResult.question, slashCommandResult.options.mapIndexed { index, s -> OptionItem(s, "$index. $s") })
-                            _viewEvents.post(TextComposerViewEvents.SlashCommandResultOk())
-                            popDraft()
-                        }
                         is ParsedCommand.ChangeTopic              -> {
                             handleChangeTopicSlashCommand(slashCommandResult)
                         }
@@ -712,16 +705,9 @@ class TextComposerViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: TextComposerViewState): TextComposerViewModel
+    interface Factory : MavericksAssistedViewModelFactory<TextComposerViewModel, TextComposerViewState> {
+        override fun create(initialState: TextComposerViewState): TextComposerViewModel
     }
 
-    companion object : MavericksViewModelFactory<TextComposerViewModel, TextComposerViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: TextComposerViewState): TextComposerViewModel {
-            val fragment: RoomDetailFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.textComposerViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<TextComposerViewModel, TextComposerViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt
index 9f98d655cc..6c315a4e76 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt
@@ -23,8 +23,8 @@ import android.view.View
 import android.view.ViewGroup
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.args
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -43,6 +43,7 @@ data class DisplayReadReceiptArgs(
 /**
  * Bottom sheet displaying list of read receipts for a given event ordered by descending timestamp
  */
+@AndroidEntryPoint
 class DisplayReadReceiptsBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
         DisplayReadReceiptsController.Listener {
@@ -53,10 +54,6 @@ class DisplayReadReceiptsBottomSheet :
 
     private lateinit var sharedActionViewModel: MessageSharedActionViewModel
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
         return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt
index 88ed101252..eea62b0907 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt
@@ -21,12 +21,13 @@ import android.content.Intent
 import android.os.Bundle
 import androidx.appcompat.widget.SearchView
 import com.airbnb.mvrx.Mavericks
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySearchBinding
 
+@AndroidEntryPoint
 class SearchActivity : VectorBaseActivity<ActivitySearchBinding>() {
 
     private val searchFragment: SearchFragment?
@@ -38,10 +39,6 @@ class SearchActivity : VectorBaseActivity<ActivitySearchBinding>() {
 
     override fun getCoordinatorLayout() = views.coordinatorLayout
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         configureToolbar(views.searchToolbar)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
index 9f34cdd679..4a285da5f2 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
@@ -47,7 +47,6 @@ data class SearchArgs(
 ) : Parcelable
 
 class SearchFragment @Inject constructor(
-        val viewModelFactory: SearchViewModel.Factory,
         private val controller: SearchResultController
 ) : VectorBaseFragment<FragmentSearchBinding>(),
         StateView.EventCallback,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt
index e4832b3876..a360b91085 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt
@@ -16,16 +16,15 @@
 
 package im.vector.app.features.home.room.detail.search
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.CancellationException
@@ -46,18 +45,11 @@ class SearchViewModel @AssistedInject constructor(
     private var nextBatch: String? = null
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SearchViewState): SearchViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SearchViewModel, SearchViewState> {
+        override fun create(initialState: SearchViewState): SearchViewModel
     }
 
-    companion object : MavericksViewModelFactory<SearchViewModel, SearchViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SearchViewState): SearchViewModel? {
-            val fragment: SearchFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<SearchViewModel, SearchViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: SearchAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt
index 6de8864f10..5e0db19d9e 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt
@@ -21,7 +21,7 @@ import android.view.View
 import android.view.ViewGroup
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -32,11 +32,11 @@ import javax.inject.Inject
 /**
  * Bottom sheet fragment that shows a message preview with list of contextual actions
  */
+@AndroidEntryPoint
 class MessageActionsBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
         MessageActionsEpoxyController.MessageActionsEpoxyControllerListener {
 
-    @Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory
     @Inject lateinit var messageActionsEpoxyController: MessageActionsEpoxyController
 
     private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class)
@@ -45,10 +45,6 @@ class MessageActionsBottomSheet :
 
     private lateinit var sharedActionViewModel: MessageSharedActionViewModel
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
         return BottomSheetGenericListBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
index a65542b920..816605ebdc 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
@@ -15,14 +15,14 @@
  */
 package im.vector.app.features.home.room.detail.timeline.action
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.Lazy
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.canReact
 import im.vector.app.core.platform.EmptyViewEvents
@@ -85,17 +85,11 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
     private val eventIdFlow = MutableStateFlow(initialState.eventId)
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: MessageActionState): MessageActionsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<MessageActionsViewModel, MessageActionState> {
+        override fun create(initialState: MessageActionState): MessageActionsViewModel
     }
 
-    companion object : MavericksViewModelFactory<MessageActionsViewModel, MessageActionState> {
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: MessageActionState): MessageActionsViewModel? {
-            val fragment: MessageActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.messageActionViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<MessageActionsViewModel, MessageActionState> by hiltMavericksViewModelFactory()
 
     init {
         observeEvent()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt
index da3a7396fd..63140edd8b 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt
@@ -22,8 +22,8 @@ import android.view.ViewGroup
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -35,18 +35,14 @@ import javax.inject.Inject
 /**
  * Bottom sheet displaying list of edits for a given event ordered by timestamp
  */
+@AndroidEntryPoint
 class ViewEditHistoryBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>() {
 
     private val viewModel: ViewEditHistoryViewModel by fragmentViewModel(ViewEditHistoryViewModel::class)
 
-    @Inject lateinit var viewEditHistoryViewModelFactory: ViewEditHistoryViewModel.Factory
     @Inject lateinit var epoxyController: ViewEditHistoryEpoxyController
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
         return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt
index 699f3cf02d..9abc67e41f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt
@@ -15,16 +15,15 @@
  */
 package im.vector.app.features.home.room.detail.timeline.edithistory
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -47,18 +46,11 @@ class ViewEditHistoryViewModel @AssistedInject constructor(
             ?: throw IllegalStateException("Shouldn't use this ViewModel without a room")
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ViewEditHistoryViewState): ViewEditHistoryViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ViewEditHistoryViewModel, ViewEditHistoryViewState> {
+        override fun create(initialState: ViewEditHistoryViewState): ViewEditHistoryViewModel
     }
 
-    companion object : MavericksViewModelFactory<ViewEditHistoryViewModel, ViewEditHistoryViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: ViewEditHistoryViewState): ViewEditHistoryViewModel? {
-            val fragment: ViewEditHistoryBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewEditHistoryViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<ViewEditHistoryViewModel, ViewEditHistoryViewState> by hiltMavericksViewModelFactory()
 
     init {
         loadHistory()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt
index 7363d07d01..a7ca467b33 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt
@@ -16,29 +16,33 @@
 
 package im.vector.app.features.home.room.detail.timeline.format
 
+import dagger.Lazy
 import im.vector.app.EmojiCompatWrapper
 import im.vector.app.R
 import im.vector.app.core.resources.ColorProvider
 import im.vector.app.core.resources.StringProvider
+import im.vector.app.features.html.EventHtmlRenderer
 import me.gujun.android.span.span
+import org.commonmark.node.Document
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageOptionsContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageType
 import org.matrix.android.sdk.api.session.room.model.message.OPTION_TYPE_BUTTONS
 import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
-import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent
-import org.matrix.android.sdk.api.session.room.timeline.isReply
+import org.matrix.android.sdk.api.session.room.timeline.getTextDisplayableContent
 import javax.inject.Inject
 
 class DisplayableEventFormatter @Inject constructor(
         private val stringProvider: StringProvider,
         private val colorProvider: ColorProvider,
         private val emojiCompatWrapper: EmojiCompatWrapper,
-        private val noticeEventFormatter: NoticeEventFormatter
+        private val noticeEventFormatter: NoticeEventFormatter,
+        private val htmlRenderer: Lazy<EventHtmlRenderer>
 ) {
 
     fun format(timelineEvent: TimelineEvent, isDm: Boolean, appendAuthor: Boolean): CharSequence {
@@ -53,54 +57,45 @@ class DisplayableEventFormatter @Inject constructor(
 
         val senderName = timelineEvent.senderInfo.disambiguatedDisplayName
 
-        when (timelineEvent.root.getClearType()) {
-            EventType.STICKER               -> {
-                return simpleFormat(senderName, stringProvider.getString(R.string.send_a_sticker), appendAuthor)
-            }
-            EventType.REACTION              -> {
-                timelineEvent.root.getClearContent().toModel<ReactionContent>()?.relatesTo?.let {
-                    val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(stringProvider.getString(R.string.sent_a_reaction, it.key))
-                    return simpleFormat(senderName, emojiSpanned, appendAuthor)
-                }
-            }
+        return when (timelineEvent.root.getClearType()) {
             EventType.MESSAGE               -> {
                 timelineEvent.getLastMessageContent()?.let { messageContent ->
                     when (messageContent.msgType) {
+                        MessageType.MSGTYPE_TEXT                 -> {
+                            val body = messageContent.getTextDisplayableContent()
+                            if (messageContent is MessageTextContent && messageContent.matrixFormattedBody.isNullOrBlank().not()) {
+                                val localFormattedBody = htmlRenderer.get().parse(body) as Document
+                                val renderedBody = htmlRenderer.get().render(localFormattedBody) ?: body
+                                simpleFormat(senderName, renderedBody, appendAuthor)
+                            } else {
+                                simpleFormat(senderName, body, appendAuthor)
+                            }
+                        }
                         MessageType.MSGTYPE_VERIFICATION_REQUEST -> {
-                            return simpleFormat(senderName, stringProvider.getString(R.string.verification_request), appendAuthor)
+                            simpleFormat(senderName, stringProvider.getString(R.string.verification_request), appendAuthor)
                         }
                         MessageType.MSGTYPE_IMAGE                -> {
-                            return simpleFormat(senderName, stringProvider.getString(R.string.sent_an_image), appendAuthor)
+                            simpleFormat(senderName, stringProvider.getString(R.string.sent_an_image), appendAuthor)
                         }
                         MessageType.MSGTYPE_AUDIO                -> {
                             if ((messageContent as? MessageAudioContent)?.voiceMessageIndicator != null) {
-                                return simpleFormat(senderName, stringProvider.getString(R.string.sent_a_voice_message), appendAuthor)
+                                simpleFormat(senderName, stringProvider.getString(R.string.sent_a_voice_message), appendAuthor)
                             } else {
-                                return simpleFormat(senderName, stringProvider.getString(R.string.sent_an_audio_file), appendAuthor)
+                                simpleFormat(senderName, stringProvider.getString(R.string.sent_an_audio_file), appendAuthor)
                             }
                         }
                         MessageType.MSGTYPE_VIDEO                -> {
-                            return simpleFormat(senderName, stringProvider.getString(R.string.sent_a_video), appendAuthor)
+                            simpleFormat(senderName, stringProvider.getString(R.string.sent_a_video), appendAuthor)
                         }
                         MessageType.MSGTYPE_FILE                 -> {
                             return simpleFormat(senderName, stringProvider.getString(R.string.sent_a_file), appendAuthor)
                         }
-                        MessageType.MSGTYPE_TEXT                 -> {
-                            return if (timelineEvent.isReply()) {
-                                // Skip reply prefix, and show important
-                                // TODO add a reply image span ?
-                                simpleFormat(senderName, timelineEvent.getTextEditableContent()
-                                        ?: messageContent.body, appendAuthor)
-                            } else {
-                                simpleFormat(senderName, messageContent.body, appendAuthor)
-                            }
-                        }
                         MessageType.MSGTYPE_RESPONSE             -> {
                             // do not show that?
-                            return span { }
+                            span { }
                         }
                         MessageType.MSGTYPE_OPTIONS              -> {
-                            return when (messageContent) {
+                            when (messageContent) {
                                 is MessageOptionsContent -> {
                                     val previewText = if (messageContent.optionType == OPTION_TYPE_BUTTONS) {
                                         stringProvider.getString(R.string.sent_a_bot_buttons)
@@ -115,15 +110,24 @@ class DisplayableEventFormatter @Inject constructor(
                             }
                         }
                         else                                     -> {
-                            return simpleFormat(senderName, messageContent.body, appendAuthor)
+                            simpleFormat(senderName, messageContent.body, appendAuthor)
                         }
                     }
-                }
+                } ?: span { }
+            }
+            EventType.STICKER               -> {
+                simpleFormat(senderName, stringProvider.getString(R.string.send_a_sticker), appendAuthor)
+            }
+            EventType.REACTION              -> {
+                timelineEvent.root.getClearContent().toModel<ReactionContent>()?.relatesTo?.let {
+                    val emojiSpanned = emojiCompatWrapper.safeEmojiSpanify(stringProvider.getString(R.string.sent_a_reaction, it.key))
+                    simpleFormat(senderName, emojiSpanned, appendAuthor)
+                } ?: span { }
             }
             EventType.KEY_VERIFICATION_CANCEL,
             EventType.KEY_VERIFICATION_DONE -> {
                 // cancel and done can appear in timeline, so should have representation
-                return simpleFormat(senderName, stringProvider.getString(R.string.sent_verification_conclusion), appendAuthor)
+                simpleFormat(senderName, stringProvider.getString(R.string.sent_verification_conclusion), appendAuthor)
             }
             EventType.KEY_VERIFICATION_START,
             EventType.KEY_VERIFICATION_ACCEPT,
@@ -131,17 +135,15 @@ class DisplayableEventFormatter @Inject constructor(
             EventType.KEY_VERIFICATION_KEY,
             EventType.KEY_VERIFICATION_READY,
             EventType.CALL_CANDIDATES       -> {
-                return span { }
+                span { }
             }
             else                            -> {
-                return span {
+                span {
                     text = noticeEventFormatter.format(timelineEvent, isDm) ?: ""
                     textStyle = "italic"
                 }
             }
         }
-
-        return span { }
     }
 
     private fun simpleFormat(senderName: String, body: CharSequence, appendAuthor: Boolean): CharSequence {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentDownloadStateTrackerBinder.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentDownloadStateTrackerBinder.kt
index abaaaf2152..caf0131144 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentDownloadStateTrackerBinder.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentDownloadStateTrackerBinder.kt
@@ -19,16 +19,16 @@ package im.vector.app.features.home.room.detail.timeline.helper
 import android.graphics.drawable.Drawable
 import androidx.vectordrawable.graphics.drawable.Animatable2Compat
 import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
+import dagger.hilt.android.scopes.ActivityScoped
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenScope
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
 import im.vector.app.features.home.room.detail.timeline.item.MessageFileItem
 import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker
 import javax.inject.Inject
 
-@ScreenScope
+@ActivityScoped
 class ContentDownloadStateTrackerBinder @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
                                                             private val messageColorProvider: MessageColorProvider,
                                                             private val errorFormatter: ErrorFormatter) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt
index 75570a67a0..0909cbe8de 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt
@@ -22,9 +22,9 @@ import android.view.ViewGroup
 import android.widget.ProgressBar
 import android.widget.TextView
 import androidx.core.view.isVisible
+import dagger.hilt.android.scopes.ActivityScoped
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenScope
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.utils.TextUtils
@@ -33,7 +33,7 @@ import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
 import org.matrix.android.sdk.api.session.room.send.SendState
 import javax.inject.Inject
 
-@ScreenScope
+@ActivityScoped
 class ContentUploadStateTrackerBinder @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
                                                           private val messageColorProvider: MessageColorProvider,
                                                           private val errorFormatter: ErrorFormatter) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt
index 52229151a0..9ec61e6054 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt
@@ -17,11 +17,11 @@
 package im.vector.app.features.home.room.detail.timeline.helper
 
 import androidx.recyclerview.widget.RecyclerView
-import im.vector.app.core.di.ScreenScope
+import dagger.hilt.android.scopes.ActivityScoped
 import javax.inject.Inject
 import kotlin.math.roundToInt
 
-@ScreenScope
+@ActivityScoped
 class TimelineMediaSizeProvider @Inject constructor() {
 
     var recyclerView: RecyclerView? = null
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/VoiceMessagePlaybackTracker.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/VoiceMessagePlaybackTracker.kt
index 446d4161e3..2e8f6d9336 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/VoiceMessagePlaybackTracker.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/VoiceMessagePlaybackTracker.kt
@@ -18,10 +18,10 @@ package im.vector.app.features.home.room.detail.timeline.helper
 
 import android.os.Handler
 import android.os.Looper
-import im.vector.app.core.di.ScreenScope
+import dagger.hilt.android.scopes.ActivityScoped
 import javax.inject.Inject
 
-@ScreenScope
+@ActivityScoped
 class VoiceMessagePlaybackTracker @Inject constructor() {
 
     private val mainHandler = Handler(Looper.getMainLooper())
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt
index 81ebd6d3de..8071ed8809 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt
@@ -23,8 +23,8 @@ import android.view.ViewGroup
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -38,21 +38,17 @@ import javax.inject.Inject
 /**
  * Bottom sheet displaying list of reactions for a given event ordered by timestamp
  */
+@AndroidEntryPoint
 class ViewReactionsBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
         ViewReactionsEpoxyController.Listener {
 
     private val viewModel: ViewReactionsViewModel by fragmentViewModel(ViewReactionsViewModel::class)
 
-    @Inject lateinit var viewReactionsViewModelFactory: ViewReactionsViewModel.Factory
     private lateinit var sharedActionViewModel: MessageSharedActionViewModel
 
     @Inject lateinit var epoxyController: ViewReactionsEpoxyController
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
         return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt
index 5baab683cf..686d767850 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt
@@ -17,32 +17,30 @@
 package im.vector.app.features.home.room.detail.timeline.reactions
 
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.core.date.DateFormatKind
 import im.vector.app.core.date.VectorDateFormatter
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
-import io.reactivex.Observable
-import io.reactivex.Single
+import kotlinx.coroutines.flow.map
 import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.room.model.ReactionAggregatedSummary
-import org.matrix.android.sdk.rx.RxRoom
-import org.matrix.android.sdk.rx.unwrap
+import org.matrix.android.sdk.flow.flow
+import org.matrix.android.sdk.flow.unwrap
 
 data class DisplayReactionsViewState(
         val eventId: String,
         val roomId: String,
         val mapReactionKeyToMemberList: Async<List<ReactionInfo>> = Uninitialized) :
-    MavericksState {
+        MavericksState {
 
     constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId)
 }
@@ -70,57 +68,42 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted
             ?: throw IllegalStateException("Shouldn't use this ViewModel without a room")
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: DisplayReactionsViewState): ViewReactionsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ViewReactionsViewModel, DisplayReactionsViewState> {
+        override fun create(initialState: DisplayReactionsViewState): ViewReactionsViewModel
     }
 
-    companion object : MavericksViewModelFactory<ViewReactionsViewModel, DisplayReactionsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: DisplayReactionsViewState): ViewReactionsViewModel? {
-            val fragment: ViewReactionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewReactionsViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<ViewReactionsViewModel, DisplayReactionsViewState> by hiltMavericksViewModelFactory()
 
     init {
         observeEventAnnotationSummaries()
     }
 
     private fun observeEventAnnotationSummaries() {
-        RxRoom(room)
+        room.flow()
                 .liveAnnotationSummary(eventId)
                 .unwrap()
-                .flatMapSingle { summaries ->
-                    Observable
-                            .fromIterable(summaries.reactionsSummary)
-                            // .filter { reactionAggregatedSummary -> isSingleEmoji(reactionAggregatedSummary.key) }
-                            .toReactionInfoList()
+                .map { annotationsSummary ->
+                    annotationsSummary.reactionsSummary
+                            .flatMap { reactionsSummary ->
+                                reactionsSummary.sourceEvents.map {
+                                    val event = room.getTimeLineEvent(it)
+                                            ?: throw RuntimeException("Your eventId is not valid")
+                                    ReactionInfo(
+                                            event.root.eventId!!,
+                                            reactionsSummary.key,
+                                            event.root.senderId ?: "",
+                                            event.senderInfo.disambiguatedDisplayName,
+                                            dateFormatter.format(event.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME)
+
+                                    )
+                                }
+                            }
                 }
                 .execute {
                     copy(mapReactionKeyToMemberList = it)
                 }
     }
 
-    private fun Observable<ReactionAggregatedSummary>.toReactionInfoList(): Single<List<ReactionInfo>> {
-        return flatMap { summary ->
-            Observable
-                    .fromIterable(summary.sourceEvents)
-                    .map {
-                        val event = room.getTimeLineEvent(it)
-                                ?: throw RuntimeException("Your eventId is not valid")
-                        ReactionInfo(
-                                event.root.eventId!!,
-                                summary.key,
-                                event.root.senderId ?: "",
-                                event.senderInfo.disambiguatedDisplayName,
-                                dateFormatter.format(event.root.originServerTs, DateFormatKind.DEFAULT_DATE_AND_TIME)
-
-                        )
-                    }
-        }.toList()
-    }
-
     override fun handle(action: EmptyAction) {
         // No op
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt
index 2fa210a748..03a0e64d9b 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomBottomSheet.kt
@@ -27,8 +27,8 @@ import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -36,9 +36,9 @@ import im.vector.app.databinding.BottomSheetRoomUpgradeBinding
 import kotlinx.parcelize.Parcelize
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class MigrateRoomBottomSheet :
-        VectorBaseBottomSheetDialogFragment<BottomSheetRoomUpgradeBinding>(),
-        MigrateRoomViewModel.Factory {
+        VectorBaseBottomSheetDialogFragment<BottomSheetRoomUpgradeBinding>() {
 
     enum class MigrationReason {
         MANUAL,
@@ -53,20 +53,12 @@ class MigrateRoomBottomSheet :
             val customDescription: CharSequence? = null
     ) : Parcelable
 
-    @Inject
-    lateinit var viewModelFactory: MigrateRoomViewModel.Factory
-
     override val showExpanded = true
 
-    @Inject
-    lateinit var errorFormatter: ErrorFormatter
+    @Inject lateinit var errorFormatter: ErrorFormatter
 
     val viewModel: MigrateRoomViewModel by fragmentViewModel()
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun invalidate() = withState(viewModel) { state ->
         views.headerText.setText(if (state.isPublic) R.string.upgrade_public_room else R.string.upgrade_private_room)
 
@@ -152,10 +144,6 @@ class MigrateRoomBottomSheet :
         }
     }
 
-    override fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
     companion object {
 
         const val REQUEST_KEY = "MigrateRoomBottomSheetRequest"
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt
index bb28836cd3..98be65c167 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt
@@ -16,15 +16,14 @@
 
 package im.vector.app.features.home.room.detail.upgrade
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.session.coroutineScope
@@ -51,20 +50,11 @@ class MigrateRoomViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel
+    interface Factory : MavericksAssistedViewModelFactory<MigrateRoomViewModel, MigrateRoomViewState> {
+        override fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel
     }
 
-    companion object : MavericksViewModelFactory<MigrateRoomViewModel, MigrateRoomViewState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: MigrateRoomViewState): MigrateRoomViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<MigrateRoomViewModel, MigrateRoomViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: MigrateRoomAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt
index 42f613d60f..aa6966254f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt
@@ -22,8 +22,8 @@ import android.view.View
 import android.view.ViewGroup
 import com.airbnb.mvrx.parentFragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -39,6 +39,7 @@ import javax.inject.Inject
 /**
  * Bottom sheet displaying active widgets in a room
  */
+@AndroidEntryPoint
 class RoomWidgetsBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
         RoomWidgetsController.Listener {
@@ -49,10 +50,6 @@ class RoomWidgetsBottomSheet :
 
     private val roomDetailViewModel: RoomDetailViewModel by parentFragmentViewModel()
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
         return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt
index a4f6f5f7c4..18618099bd 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt
@@ -20,8 +20,8 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import androidx.appcompat.widget.SearchView
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityFilteredRoomsBinding
@@ -29,6 +29,7 @@ import im.vector.app.features.home.RoomListDisplayMode
 import im.vector.app.features.home.room.list.RoomListFragment
 import im.vector.app.features.home.room.list.RoomListParams
 
+@AndroidEntryPoint
 class FilteredRoomsActivity : VectorBaseActivity<ActivityFilteredRoomsBinding>() {
 
     private val roomListFragment: RoomListFragment?
@@ -40,10 +41,6 @@ class FilteredRoomsActivity : VectorBaseActivity<ActivityFilteredRoomsBinding>()
 
     override fun getCoordinatorLayout() = views.coordinatorLayout
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         configureToolbar(views.filteredRoomsToolbar)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListDisplayModeFilter.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListDisplayModeFilter.kt
index 03d6c89e40..a09e51d617 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListDisplayModeFilter.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListDisplayModeFilter.kt
@@ -16,8 +16,8 @@
 
 package im.vector.app.features.home.room.list
 
+import androidx.core.util.Predicate
 import im.vector.app.features.home.RoomListDisplayMode
-import io.reactivex.functions.Predicate
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
index 9eb181b7a8..6283fee1ba 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt
@@ -24,6 +24,7 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.core.content.ContextCompat
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import androidx.preference.PreferenceManager
 import androidx.recyclerview.widget.ConcatAdapter
 import androidx.recyclerview.widget.LinearLayoutManager
@@ -53,6 +54,8 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
 import im.vector.app.features.home.room.list.widget.NotifsFabMenuView
 import im.vector.app.features.notifications.NotificationDrawerManager
 import im.vector.app.features.settings.VectorPreferences
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.extensions.orTrue
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
@@ -69,7 +72,6 @@ data class RoomListParams(
 class RoomListFragment @Inject constructor(
         private val appStateHandler: AppStateHandler,
         private val pagedControllerFactory: RoomSummaryPagedControllerFactory,
-        val roomListViewModelFactory: RoomListViewModel.Factory,
         private val notificationDrawerManager: NotificationDrawerManager,
         private val vectorPreferences: VectorPreferences,
         private val footerController: RoomListFooterController,
@@ -128,9 +130,9 @@ class RoomListFragment @Inject constructor(
         views.createChatFabMenu.listener = this
 
         sharedActionViewModel
-                .observe()
-                .subscribe { handleQuickActions(it) }
-                .disposeOnDestroyView()
+                .stream()
+                .onEach { handleQuickActions(it) }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         roomListViewModel.onEach(RoomListViewState::roomMembershipChanges) { ms ->
             // it's for invites local echo
@@ -533,7 +535,7 @@ class RoomListFragment @Inject constructor(
     }
 
     override fun onAcceptRoomInvitation(room: RoomSummary) {
-        notificationDrawerManager.clearMemberShipNotificationForRoom(room.roomId)
+        notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
         roomListViewModel.handle(RoomListAction.AcceptInvitation(room))
     }
 
@@ -546,7 +548,7 @@ class RoomListFragment @Inject constructor(
     }
 
     override fun onRejectRoomInvitation(room: RoomSummary) {
-        notificationDrawerManager.clearMemberShipNotificationForRoom(room.roomId)
+        notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
         roomListViewModel.handle(RoomListAction.RejectInvitation(room))
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt
index 274cf7c869..edd4c86060 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListNameFilter.kt
@@ -16,7 +16,7 @@
 
 package im.vector.app.features.home.room.list
 
-import io.reactivex.functions.Predicate
+import androidx.core.util.Predicate
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import javax.inject.Inject
 
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt
index 2b3152f8cf..c98f613c40 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt
@@ -20,6 +20,4 @@ import im.vector.app.features.home.RoomListDisplayMode
 
 interface RoomListSectionBuilder {
     fun buildSections(mode: RoomListDisplayMode): List<RoomsSection>
-
-    fun dispose()
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt
index 4d40ffb329..0a093c3a5a 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt
@@ -17,6 +17,7 @@
 package im.vector.app.features.home.room.list
 
 import androidx.annotation.StringRes
+import androidx.lifecycle.asFlow
 import im.vector.app.AppStateHandler
 import im.vector.app.R
 import im.vector.app.RoomGroupingMethod
@@ -24,17 +25,21 @@ import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.home.RoomListDisplayMode
 import im.vector.app.features.invite.AutoAcceptInvites
 import im.vector.app.features.invite.showInvites
-import io.reactivex.disposables.CompositeDisposable
-import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.query.RoomCategoryFilter
 import org.matrix.android.sdk.api.query.RoomTagQueryFilter
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
 import org.matrix.android.sdk.api.session.room.model.Membership
-import org.matrix.android.sdk.rx.asObservable
 
 class RoomListSectionBuilderGroup(
+        private val coroutineScope: CoroutineScope,
         private val session: Session,
         private val stringProvider: StringProvider,
         private val appStateHandler: AppStateHandler,
@@ -42,8 +47,6 @@ class RoomListSectionBuilderGroup(
         private val onUpdatable: (UpdatableLivePageResult) -> Unit
 ) : RoomListSectionBuilder {
 
-    private val disposables = CompositeDisposable()
-
     override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
         val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
         val sections = mutableListOf<RoomsSection>()
@@ -107,16 +110,14 @@ class RoomListSectionBuilderGroup(
 
         appStateHandler.selectedRoomGroupingObservable
                 .distinctUntilChanged()
-                .subscribe { groupingMethod ->
+                .onEach { groupingMethod ->
                     val selectedGroupId = (groupingMethod.orNull() as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
                     activeGroupAwareQueries.onEach { updater ->
                         updater.updateQuery { query ->
                             query.copy(activeGroupId = selectedGroupId)
                         }
                     }
-                }.also {
-                    disposables.add(it)
-                }
+                }.launchIn(coroutineScope)
 
         return sections
     }
@@ -313,15 +314,14 @@ class RoomListSectionBuilderGroup(
                             }.livePagedList
                             .let { livePagedList ->
                                 // use it also as a source to update count
-                                livePagedList.asObservable()
-                                        .observeOn(Schedulers.computation())
-                                        .subscribe {
+                                livePagedList.asFlow()
+                                        .onEach {
                                             sections.find { it.sectionName == name }
                                                     ?.notificationCount
                                                     ?.postValue(session.getNotificationCountForRooms(roomQueryParams))
-                                        }.also {
-                                            disposables.add(it)
                                         }
+                                        .flowOn(Dispatchers.Default)
+                                        .launchIn(coroutineScope)
 
                                 sections.add(
                                         RoomsSection(
@@ -342,8 +342,4 @@ class RoomListSectionBuilderGroup(
                 .build()
                 .let { block(it) }
     }
-
-    override fun dispose() {
-        disposables.dispose()
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt
index 00fa56c4f4..23a01b5845 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt
@@ -19,6 +19,7 @@ package im.vector.app.features.home.room.list
 import androidx.annotation.StringRes
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.asFlow
 import androidx.lifecycle.liveData
 import androidx.paging.PagedList
 import com.airbnb.mvrx.Async
@@ -29,12 +30,15 @@ import im.vector.app.features.home.RoomListDisplayMode
 import im.vector.app.features.invite.AutoAcceptInvites
 import im.vector.app.features.invite.showInvites
 import im.vector.app.space
-import io.reactivex.Observable
-import io.reactivex.disposables.CompositeDisposable
-import io.reactivex.rxkotlin.Observables
-import io.reactivex.schedulers.Schedulers
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.query.ActiveSpaceFilter
 import org.matrix.android.sdk.api.query.RoomCategoryFilter
@@ -44,7 +48,7 @@ import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
-import org.matrix.android.sdk.rx.asObservable
+import timber.log.Timber
 
 class RoomListSectionBuilderSpace(
         private val session: Session,
@@ -57,8 +61,6 @@ class RoomListSectionBuilderSpace(
         private val onlyOrphansInHome: Boolean = false
 ) : RoomListSectionBuilder {
 
-    private val disposables = CompositeDisposable()
-
     private val pagedListConfig = PagedList.Config.Builder()
             .setPageSize(10)
             .setInitialLoadSizeHint(20)
@@ -135,14 +137,12 @@ class RoomListSectionBuilderSpace(
 
         appStateHandler.selectedRoomGroupingObservable
                 .distinctUntilChanged()
-                .subscribe { groupingMethod ->
+                .onEach { groupingMethod ->
                     val selectedSpace = groupingMethod.orNull()?.space()
                     activeSpaceAwareQueries.onEach { updater ->
                         updater.updateForSpaceId(selectedSpace?.roomId)
                     }
-                }.also {
-                    disposables.add(it)
-                }
+                }.launchIn(viewModelScope)
 
         return sections
     }
@@ -215,51 +215,7 @@ class RoomListSectionBuilderSpace(
             it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
         }
 
-        // add suggested rooms
-        val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
-                appStateHandler.selectedRoomGroupingObservable
-                        .distinctUntilChanged()
-                        .switchMap { groupingMethod ->
-                            val selectedSpace = groupingMethod.orNull()?.space()
-                            if (selectedSpace == null) {
-                                Observable.just(emptyList())
-                            } else {
-                                liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
-                                    val spaceSum = tryOrNull {
-                                        session.spaceService()
-                                                .querySpaceChildren(selectedSpace.roomId, suggestedOnly = true, null, null)
-                                    }
-                                    val value = spaceSum?.children.orEmpty().distinctBy { it.childRoomId }
-                                    // i need to check if it's already joined.
-                                    val filtered = value.filter {
-                                        session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
-                                    }
-                                    emit(filtered)
-                                }.asObservable()
-                            }
-                        }
-
-        val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
-        Observables.combineLatest(
-                suggestedRoomsObservable,
-                suggestedRoomJoiningState.asObservable()
-        ) { rooms, joinStates ->
-            SuggestedRoomInfo(
-                    rooms,
-                    joinStates
-            )
-        }.subscribe {
-            liveSuggestedRooms.postValue(it)
-        }.also {
-            disposables.add(it)
-        }
-        sections.add(
-                RoomsSection(
-                        sectionName = stringProvider.getString(R.string.suggested_header),
-                        liveSuggested = liveSuggestedRooms,
-                        notifyOfLocalEcho = false
-                )
-        )
+        addSuggestedRoomsSection(sections)
     }
 
     private fun buildRoomsSections(sections: MutableList<RoomsSection>,
@@ -338,14 +294,18 @@ class RoomListSectionBuilderSpace(
             it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
         }
 
+        addSuggestedRoomsSection(sections)
+    }
+
+    private fun addSuggestedRoomsSection(sections: MutableList<RoomsSection>) {
         // add suggested rooms
-        val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
+        val suggestedRoomsFlow = // MutableLiveData<List<SpaceChildInfo>>()
                 appStateHandler.selectedRoomGroupingObservable
                         .distinctUntilChanged()
-                        .switchMap { groupingMethod ->
+                        .flatMapLatest { groupingMethod ->
                             val selectedSpace = groupingMethod.orNull()?.space()
                             if (selectedSpace == null) {
-                                Observable.just(emptyList())
+                                flowOf(emptyList())
                             } else {
                                 liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
                                     val spaceSum = tryOrNull {
@@ -358,24 +318,23 @@ class RoomListSectionBuilderSpace(
                                         session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
                                     }
                                     emit(filtered)
-                                }.asObservable()
+                                }.asFlow()
                             }
                         }
 
         val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
-        Observables.combineLatest(
-                suggestedRoomsObservable,
-                suggestedRoomJoiningState.asObservable()
+        combine(
+                suggestedRoomsFlow,
+                suggestedRoomJoiningState.asFlow()
         ) { rooms, joinStates ->
             SuggestedRoomInfo(
                     rooms,
                     joinStates
             )
-        }.subscribe {
+        }.onEach {
             liveSuggestedRooms.postValue(it)
-        }.also {
-            disposables.add(it)
-        }
+        }.launchIn(viewModelScope)
+
         sections.add(
                 RoomsSection(
                         sectionName = stringProvider.getString(R.string.suggested_header),
@@ -492,9 +451,9 @@ class RoomListSectionBuilderSpace(
                     }.livePagedList
                             .let { livePagedList ->
                                 // use it also as a source to update count
-                                livePagedList.asObservable()
-                                        .observeOn(Schedulers.computation())
-                                        .subscribe {
+                                livePagedList.asFlow()
+                                        .onEach {
+                                            Timber.v("Thread space list: ${Thread.currentThread()}")
                                             sections.find { it.sectionName == name }
                                                     ?.notificationCount
                                                     ?.postValue(
@@ -506,9 +465,9 @@ class RoomListSectionBuilderSpace(
                                                                 )
                                                             }
                                                     )
-                                        }.also {
-                                            disposables.add(it)
                                         }
+                                        .flowOn(Dispatchers.Default)
+                                        .launchIn(viewModelScope)
 
                                 sections.add(
                                         RoomsSection(
@@ -551,8 +510,4 @@ class RoomListSectionBuilderSpace(
             RoomListViewModel.SpaceFilterStrategy.NONE                  -> this
         }
     }
-
-    override fun dispose() {
-        disposables.dispose()
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt
index 70d3638238..c1e3e2adf0 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt
@@ -19,13 +19,16 @@ package im.vector.app.features.home.room.list
 import androidx.lifecycle.MutableLiveData
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
 import im.vector.app.RoomGroupingMethod
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -46,10 +49,9 @@ import org.matrix.android.sdk.api.session.room.state.isPublic
 import org.matrix.android.sdk.api.util.toMatrixItem
 import org.matrix.android.sdk.flow.flow
 import timber.log.Timber
-import javax.inject.Inject
 
-class RoomListViewModel @Inject constructor(
-        initialState: RoomListViewState,
+class RoomListViewModel @AssistedInject constructor(
+        @Assisted initialState: RoomListViewState,
         private val session: Session,
         private val stringProvider: StringProvider,
         private val appStateHandler: AppStateHandler,
@@ -57,8 +59,9 @@ class RoomListViewModel @Inject constructor(
         private val autoAcceptInvites: AutoAcceptInvites
 ) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
 
-    interface Factory {
-        fun create(initialState: RoomListViewState): RoomListViewModel
+    @AssistedFactory
+    interface Factory : MavericksAssistedViewModelFactory<RoomListViewModel, RoomListViewState> {
+        override fun create(initialState: RoomListViewState): RoomListViewModel
     }
 
     private var updatableQuery: UpdatableLivePageResult? = null
@@ -115,14 +118,7 @@ class RoomListViewModel @Inject constructor(
                 }
     }
 
-    companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel {
-            val fragment: RoomListFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.roomListViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> by hiltMavericksViewModelFactory()
 
     private val roomListSectionBuilder = if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) {
         RoomListSectionBuilderSpace(
@@ -139,6 +135,7 @@ class RoomListViewModel @Inject constructor(
         )
     } else {
         RoomListSectionBuilderGroup(
+                viewModelScope,
                 session,
                 stringProvider,
                 appStateHandler,
@@ -201,7 +198,7 @@ class RoomListViewModel @Inject constructor(
         }
         updatableQuery?.updateQuery {
             it.copy(
-                    displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
+                    displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.NORMALIZED)
             )
         }
     }
@@ -358,9 +355,4 @@ class RoomListViewModel @Inject constructor(
             _viewEvents.post(value)
         }
     }
-
-    override fun onCleared() {
-        super.onCleared()
-        roomListSectionBuilder.dispose()
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModelFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModelFactory.kt
deleted file mode 100644
index e017a8fe08..0000000000
--- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModelFactory.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2019 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.features.home.room.list
-
-import im.vector.app.AppStateHandler
-import im.vector.app.core.resources.StringProvider
-import im.vector.app.features.invite.AutoAcceptInvites
-import im.vector.app.features.settings.VectorPreferences
-import org.matrix.android.sdk.api.session.Session
-import javax.inject.Inject
-import javax.inject.Provider
-
-class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
-                                                   private val appStateHandler: AppStateHandler,
-                                                   private val stringProvider: StringProvider,
-                                                   private val vectorPreferences: VectorPreferences,
-                                                   private val autoAcceptInvites: AutoAcceptInvites) :
-    RoomListViewModel.Factory {
-
-    override fun create(initialState: RoomListViewState): RoomListViewModel {
-        return RoomListViewModel(
-                initialState = initialState,
-                session = session.get(),
-                stringProvider = stringProvider,
-                appStateHandler = appStateHandler,
-                vectorPreferences = vectorPreferences,
-                autoAcceptInvites = autoAcceptInvites
-        )
-    }
-}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt
index 8c1bdc086f..014ce14c95 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt
@@ -26,8 +26,8 @@ import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
@@ -56,13 +56,13 @@ data class RoomListActionsArgs(
 /**
  * Bottom sheet fragment that shows room information with list of contextual actions
  */
+@AndroidEntryPoint
 class RoomListQuickActionsBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
         RoomListQuickActionsEpoxyController.Listener {
 
     private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
     @Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
-    @Inject lateinit var roomNotificationSettingsViewModelFactory: RoomNotificationSettingsViewModel.Factory
     @Inject lateinit var roomListActionsEpoxyController: RoomListQuickActionsEpoxyController
     @Inject lateinit var navigator: Navigator
     @Inject lateinit var errorFormatter: ErrorFormatter
@@ -72,10 +72,6 @@ class RoomListQuickActionsBottomSheet :
 
     override val showExpanded = true
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
         return BottomSheetGenericListBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt
index deee0c4cf5..9223485eff 100644
--- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt
@@ -16,20 +16,20 @@
 
 package im.vector.app.features.homeserver
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import im.vector.app.core.di.HasScreenInjector
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.SingletonEntryPoint
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.raw.wellknown.getElementWellknown
 import im.vector.app.features.raw.wellknown.isE2EByDefault
-import im.vector.app.features.userdirectory.UserListFragment
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.extensions.tryOrNull
@@ -44,19 +44,14 @@ class HomeServerCapabilitiesViewModel @AssistedInject constructor(
 ) : VectorViewModel<HomeServerCapabilitiesViewState, EmptyAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel
+    interface Factory : MavericksAssistedViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> {
+        override fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel
     }
 
-    companion object : MavericksViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> {
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel? {
-            val fragment: UserListFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.homeServerCapabilitiesViewModelFactory.create(state)
-        }
+    companion object : MavericksViewModelFactory<HomeServerCapabilitiesViewModel, HomeServerCapabilitiesViewState> by hiltMavericksViewModelFactory() {
 
-        override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState? {
-            val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getSafeActiveSession()
+        override fun initialState(viewModelContext: ViewModelContext): HomeServerCapabilitiesViewState {
+            val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getSafeActiveSession()
             return HomeServerCapabilitiesViewState(
                     capabilities = session?.getHomeServerCapabilities() ?: HomeServerCapabilities()
             )
@@ -64,6 +59,7 @@ class HomeServerCapabilitiesViewModel @AssistedInject constructor(
     }
 
     init {
+
         initAdminE2eByDefault()
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt
index dd07319e9f..1bf1c12a48 100644
--- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt
@@ -21,11 +21,12 @@ import android.content.Intent
 import android.os.Bundle
 import android.os.Parcelable
 import android.view.View
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
@@ -37,14 +38,12 @@ import im.vector.app.core.utils.onPermissionDeniedSnackbar
 import im.vector.app.core.utils.registerForPermissionsResult
 import im.vector.app.core.utils.toast
 import im.vector.app.features.contactsbook.ContactsBookFragment
-import im.vector.app.features.contactsbook.ContactsBookViewModel
-import im.vector.app.features.contactsbook.ContactsBookViewState
 import im.vector.app.features.userdirectory.UserListFragment
 import im.vector.app.features.userdirectory.UserListFragmentArgs
 import im.vector.app.features.userdirectory.UserListSharedAction
 import im.vector.app.features.userdirectory.UserListSharedActionViewModel
-import im.vector.app.features.userdirectory.UserListViewModel
-import im.vector.app.features.userdirectory.UserListViewState
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.failure.Failure
 import java.net.HttpURLConnection
@@ -53,26 +52,13 @@ import javax.inject.Inject
 @Parcelize
 data class InviteUsersToRoomArgs(val roomId: String) : Parcelable
 
-class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Factory, ContactsBookViewModel.Factory, InviteUsersToRoomViewModel.Factory {
+@AndroidEntryPoint
+class InviteUsersToRoomActivity : SimpleFragmentActivity() {
 
     private val viewModel: InviteUsersToRoomViewModel by viewModel()
     private lateinit var sharedActionViewModel: UserListSharedActionViewModel
-    @Inject lateinit var userListViewModelFactory: UserListViewModel.Factory
-    @Inject lateinit var inviteUsersToRoomViewModelFactory: InviteUsersToRoomViewModel.Factory
-    @Inject lateinit var contactsBookViewModelFactory: ContactsBookViewModel.Factory
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
-    override fun create(initialState: UserListViewState) = userListViewModelFactory.create(initialState)
-
-    override fun create(initialState: ContactsBookViewState) = contactsBookViewModelFactory.create(initialState)
-
-    override fun create(initialState: InviteUsersToRoomViewState) = inviteUsersToRoomViewModelFactory.create(initialState)
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
@@ -80,8 +66,8 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fa
 
         sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         UserListSharedAction.Close                 -> finish()
                         UserListSharedAction.GoBack                -> onBackPressed()
@@ -92,7 +78,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fa
                         }
                     }
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
         if (isFirstCreation()) {
             addFragment(
                     R.id.container,
diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt
index fd06614950..891194040e 100644
--- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt
@@ -16,14 +16,13 @@
 
 package im.vector.app.features.invite
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.userdirectory.PendingSelection
@@ -43,21 +42,11 @@ class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted
     private val room = session.getRoom(initialState.roomId)!!
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: InviteUsersToRoomViewState): InviteUsersToRoomViewModel
+    interface Factory : MavericksAssistedViewModelFactory<InviteUsersToRoomViewModel, InviteUsersToRoomViewState> {
+        override fun create(initialState: InviteUsersToRoomViewState): InviteUsersToRoomViewModel
     }
 
-    companion object : MavericksViewModelFactory<InviteUsersToRoomViewModel, InviteUsersToRoomViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: InviteUsersToRoomViewState): InviteUsersToRoomViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<InviteUsersToRoomViewModel, InviteUsersToRoomViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: InviteUsersToRoomAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt b/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt
index 09eff756d5..73876bf6e9 100644
--- a/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt
+++ b/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt
@@ -18,11 +18,14 @@ package im.vector.app.features.invite
 
 import im.vector.app.ActiveSessionDataSource
 import im.vector.app.features.session.coroutineScope
-import io.reactivex.disposables.Disposable
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.async
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -51,7 +54,8 @@ class InvitesAcceptor @Inject constructor(
         private val autoAcceptInvites: AutoAcceptInvites
 ) : Session.Listener {
 
-    private lateinit var activeSessionDisposable: Disposable
+    private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
+
     private val shouldRejectRoomIds = mutableSetOf<String>()
     private val activeSessionIds = mutableSetOf<String>()
     private val semaphore = Semaphore(1)
@@ -61,13 +65,14 @@ class InvitesAcceptor @Inject constructor(
     }
 
     private fun observeActiveSession() {
-        activeSessionDisposable = sessionDataSource.observe()
+        sessionDataSource.stream()
                 .distinctUntilChanged()
-                .subscribe {
+                .onEach {
                     it.orNull()?.let { session ->
                         onSessionActive(session)
                     }
                 }
+                .launchIn(coroutineScope)
     }
 
     private fun onSessionActive(session: Session) {
diff --git a/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt b/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt
index 22f9e9a18c..d9f1ad343b 100644
--- a/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt
+++ b/vector/src/main/java/im/vector/app/features/invite/VectorInviteView.kt
@@ -21,8 +21,8 @@ import android.util.AttributeSet
 import android.view.View
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.updateLayoutParams
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.HasScreenInjector
 import im.vector.app.databinding.VectorInviteViewBinding
 import im.vector.app.features.home.AvatarRenderer
 import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
 import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class VectorInviteView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
     ConstraintLayout(context, attrs, defStyle) {
 
@@ -49,9 +50,6 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib
     var callback: Callback? = null
 
     init {
-        if (context is HasScreenInjector) {
-            context.injector().inject(this)
-        }
         inflate(context, R.layout.vector_invite_view, this)
         views = VectorInviteViewBinding.bind(this)
         views.inviteAcceptView.commonClicked = { callback?.onAcceptInvite() }
diff --git a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt
index 39105185b1..c22f8eb779 100644
--- a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt
@@ -20,9 +20,9 @@ import android.content.Intent
 import android.net.Uri
 import androidx.lifecycle.lifecycleScope
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.core.utils.toast
@@ -38,6 +38,7 @@ import javax.inject.Inject
 /**
  * Dummy activity used to dispatch the vector URL links.
  */
+@AndroidEntryPoint
 class LinkHandlerActivity : VectorBaseActivity<ActivityProgressBinding>() {
 
     @Inject lateinit var sessionHolder: ActiveSessionHolder
@@ -46,10 +47,6 @@ class LinkHandlerActivity : VectorBaseActivity<ActivityProgressBinding>() {
 
     override fun getBinding() = ActivityProgressBinding.inflate(layoutInflater)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         handleIntent()
     }
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt
index a01e02f4e0..a357caf8fa 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt
@@ -20,7 +20,6 @@ import android.content.Context
 import android.content.Intent
 import android.view.View
 import android.view.ViewGroup
-import androidx.annotation.CallSuper
 import androidx.core.view.ViewCompat
 import androidx.core.view.children
 import androidx.core.view.isVisible
@@ -31,8 +30,8 @@ import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.POP_BACK_STACK_EXCLUSIVE
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
@@ -48,22 +47,15 @@ import im.vector.app.features.pin.UnlockedActivity
 import org.matrix.android.sdk.api.auth.registration.FlowResult
 import org.matrix.android.sdk.api.auth.registration.Stage
 import org.matrix.android.sdk.api.extensions.tryOrNull
-import javax.inject.Inject
 
 /**
  * The LoginActivity manages the fragment navigation and also display the loading View
  */
+@AndroidEntryPoint
 open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarConfigurable, UnlockedActivity {
 
     private val loginViewModel: LoginViewModel by viewModel()
 
-    @Inject lateinit var loginViewModelFactory: LoginViewModel.Factory
-
-    @CallSuper
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     private val enterAnim = R.anim.enter_fade_in
     private val exitAnim = R.anim.exit_fade_out
 
@@ -93,10 +85,9 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
             addFirstFragment()
         }
 
-        loginViewModel
-                .subscribe(this) {
-                    updateWithState(it)
-                }
+        loginViewModel.onEach {
+            updateWithState(it)
+        }
 
         loginViewModel.observeViewEvents { handleLoginViewEvents(it) }
 
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt
index 0fbabcd12b..3a3b169974 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginFragment.kt
@@ -25,21 +25,24 @@ import android.view.inputmethod.EditorInfo
 import androidx.autofill.HintConstants
 import androidx.core.text.isDigitsOnly
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.hidePassword
 import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.databinding.FragmentLoginBinding
-import io.reactivex.Observable
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.api.failure.isInvalidPassword
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -193,7 +196,7 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
 
             if (state.loginMode is LoginMode.SsoAndPassword) {
                 views.loginSocialLoginContainer.isVisible = true
-                views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders
+                views.loginSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders?.sorted()
                 views.loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
                     override fun onProviderSelected(id: String?) {
                         loginViewModel.getSsoUrl(
@@ -224,20 +227,18 @@ class LoginFragment @Inject constructor() : AbstractSSOLoginFragment<FragmentLog
 
     private fun setupSubmitButton() {
         views.loginSubmit.setOnClickListener { submit() }
-        Observable
-                .combineLatest(
-                        views.loginField.textChanges().map { it.trim().isNotEmpty() },
-                        views.passwordField.textChanges().map { it.isNotEmpty() },
-                        { isLoginNotEmpty, isPasswordNotEmpty ->
-                            isLoginNotEmpty && isPasswordNotEmpty
-                        }
-                )
-                .subscribeBy {
+        combine(
+                views.loginField.textChanges().map { it.trim().isNotEmpty() },
+                views.passwordField.textChanges().map { it.isNotEmpty() }
+        ) { isLoginNotEmpty, isPasswordNotEmpty ->
+            isLoginNotEmpty && isPasswordNotEmpty
+        }
+                .onEach {
                     views.loginFieldTil.error = null
                     views.passwordFieldTil.error = null
                     views.loginSubmit.isEnabled = it
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun forgetPasswordClicked() {
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt
index 925a5c05ab..150cb700cb 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginGenericTextInputFormFragment.kt
@@ -25,19 +25,22 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.autofill.HintConstants
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.args
 import com.google.i18n.phonenumbers.NumberParseException
 import com.google.i18n.phonenumbers.PhoneNumberUtil
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.isEmail
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.databinding.FragmentLoginGenericTextInputFormBinding
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.is401
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 enum class TextInputFormFragmentMode {
@@ -93,10 +96,10 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra
 
     private fun setupTil() {
         views.loginGenericTextInputFormTextInput.textChanges()
-                .subscribe {
+                .onEach {
                     views.loginGenericTextInputFormTil.error = null
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun setupUi() {
@@ -195,10 +198,10 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra
     private fun setupSubmitButton() {
         views.loginGenericTextInputFormSubmit.isEnabled = false
         views.loginGenericTextInputFormTextInput.textChanges()
-                .subscribe {
+                .onEach {
                     views.loginGenericTextInputFormSubmit.isEnabled = isInputValid(it)
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun isInputValid(input: CharSequence): Boolean {
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt
index cc113b1eed..a06a569f44 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt
@@ -20,19 +20,22 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.hidePassword
 import im.vector.app.core.extensions.isEmail
 import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.databinding.FragmentLoginResetPasswordBinding
-import io.reactivex.Observable
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -59,21 +62,18 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment<F
 
     private fun setupSubmitButton() {
         views.resetPasswordSubmit.setOnClickListener { submit() }
-
-        Observable
-                .combineLatest(
-                        views.resetPasswordEmail.textChanges().map { it.isEmail() },
-                        views.passwordField.textChanges().map { it.isNotEmpty() },
-                        { isEmail, isPasswordNotEmpty ->
-                            isEmail && isPasswordNotEmpty
-                        }
-                )
-                .subscribeBy {
+        combine(
+                views.resetPasswordEmail.textChanges().map { it.isEmail() },
+                views.passwordField.textChanges().map { it.isNotEmpty() }
+        ) { isEmail, isPasswordNotEmpty ->
+            isEmail && isPasswordNotEmpty
+        }
+                .onEach {
                     views.resetPasswordEmailTil.error = null
                     views.passwordFieldTil.error = null
                     views.resetPasswordSubmit.isEnabled = it
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun submit() {
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt
index ebe82b1163..65ad7af346 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginServerUrlFormFragment.kt
@@ -25,15 +25,18 @@ import android.view.inputmethod.EditorInfo
 import android.widget.ArrayAdapter
 import androidx.core.view.isInvisible
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.google.android.material.textfield.TextInputLayout
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.BuildConfig
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.utils.ensureProtocol
 import im.vector.app.core.utils.openUrlInChromeCustomTab
 import im.vector.app.databinding.FragmentLoginServerUrlFormBinding
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.failure.Failure
+import reactivecircus.flowbinding.android.widget.textChanges
 import java.net.UnknownHostException
 import javax.inject.Inject
 
@@ -61,11 +64,11 @@ class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment<F
 
     private fun setupHomeServerField() {
         views.loginServerUrlFormHomeServerUrl.textChanges()
-                .subscribe {
+                .onEach {
                     views.loginServerUrlFormHomeServerUrlTil.error = null
                     views.loginServerUrlFormSubmit.isEnabled = it.isNotBlank()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.loginServerUrlFormHomeServerUrl.setOnEditorActionListener { _, actionId, _ ->
             if (actionId == EditorInfo.IME_ACTION_DONE) {
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt
index c69f539099..5f488a3523 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginSignUpSignInSelectionFragment.kt
@@ -72,7 +72,7 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLogi
         when (state.loginMode) {
             is LoginMode.SsoAndPassword -> {
                 views.loginSignupSigninSignInSocialLoginContainer.isVisible = true
-                views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders()
+                views.loginSignupSigninSocialLoginButtons.ssoIdentityProviders = state.loginMode.ssoIdentityProviders()?.sorted()
                 views.loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
                     override fun onProviderSelected(id: String?) {
                         loginViewModel.getSsoUrl(
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
index ca126570ff..bfa924c155 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
@@ -18,25 +18,23 @@ package im.vector.app.features.login
 
 import android.content.Context
 import android.net.Uri
-import androidx.fragment.app.FragmentActivity
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.utils.ensureTrailingSlash
-import im.vector.app.features.signout.soft.SoftLogoutActivity
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.MatrixPatterns.getDomain
@@ -71,10 +69,12 @@ class LoginViewModel @AssistedInject constructor(
 ) : VectorViewModel<LoginViewState, LoginAction, LoginViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: LoginViewState): LoginViewModel
+    interface Factory : MavericksAssistedViewModelFactory<LoginViewModel, LoginViewState> {
+        override fun create(initialState: LoginViewState): LoginViewModel
     }
 
+    companion object : MavericksViewModelFactory<LoginViewModel, LoginViewState> by hiltMavericksViewModelFactory()
+
     init {
         getKnownCustomHomeServersUrls()
     }
@@ -85,18 +85,6 @@ class LoginViewModel @AssistedInject constructor(
         }
     }
 
-    companion object : MavericksViewModelFactory<LoginViewModel, LoginViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: LoginViewState): LoginViewModel? {
-            return when (val activity: FragmentActivity = (viewModelContext as ActivityViewModelContext).activity()) {
-                is LoginActivity      -> activity.loginViewModelFactory.create(state)
-                is SoftLogoutActivity -> activity.loginViewModelFactory.create(state)
-                else                  -> error("Invalid Activity")
-            }
-        }
-    }
-
     // Store the last action, to redo it after user has trusted the untrusted certificate
     private var lastAction: LoginAction? = null
     private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginActivity2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginActivity2.kt
index a640f02279..8f1b20aa7f 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginActivity2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginActivity2.kt
@@ -20,7 +20,6 @@ import android.content.Context
 import android.content.Intent
 import android.view.View
 import android.view.ViewGroup
-import androidx.annotation.CallSuper
 import androidx.core.view.ViewCompat
 import androidx.core.view.children
 import androidx.core.view.isVisible
@@ -30,8 +29,8 @@ import androidx.fragment.app.FragmentTransaction
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.POP_BACK_STACK_EXCLUSIVE
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
@@ -55,22 +54,15 @@ import im.vector.app.features.pin.UnlockedActivity
 import org.matrix.android.sdk.api.auth.registration.FlowResult
 import org.matrix.android.sdk.api.auth.registration.Stage
 import org.matrix.android.sdk.api.extensions.tryOrNull
-import javax.inject.Inject
 
 /**
  * The LoginActivity manages the fragment navigation and also display the loading View
  */
+@AndroidEntryPoint
 open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarConfigurable, UnlockedActivity {
 
     private val loginViewModel: LoginViewModel2 by viewModel()
 
-    @Inject lateinit var loginViewModelFactory: LoginViewModel2.Factory
-
-    @CallSuper
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     private val enterAnim = R.anim.enter_fade_in
     private val exitAnim = R.anim.exit_fade_out
 
@@ -100,10 +92,9 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
             addFirstFragment()
         }
 
-        loginViewModel
-                .subscribe(this) {
-                    updateWithState(it)
-                }
+        loginViewModel.onEach {
+            updateWithState(it)
+        }
 
         loginViewModel.observeViewEvents { handleLoginViewEvents(it) }
 
@@ -209,19 +200,19 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
                 // Go back to the login fragment
                 supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
             }
-            is LoginViewEvents2.OnSendEmailSuccess       ->
+            is LoginViewEvents2.OnSendEmailSuccess                         ->
                 addFragmentToBackstack(R.id.loginFragmentContainer,
                         LoginWaitForEmailFragment2::class.java,
                         LoginWaitForEmailFragmentArgument(event.email),
                         tag = FRAGMENT_REGISTRATION_STAGE_TAG,
                         option = commonOption)
-            is LoginViewEvents2.OpenSigninPasswordScreen -> {
+            is LoginViewEvents2.OpenSigninPasswordScreen                   -> {
                 addFragmentToBackstack(R.id.loginFragmentContainer,
                         LoginFragmentSigninPassword2::class.java,
                         tag = FRAGMENT_LOGIN_TAG,
                         option = commonOption)
             }
-            is LoginViewEvents2.OpenSignupPasswordScreen -> {
+            is LoginViewEvents2.OpenSignupPasswordScreen                   -> {
                 addFragmentToBackstack(R.id.loginFragmentContainer,
                         LoginFragmentSignupPassword2::class.java,
                         tag = FRAGMENT_REGISTRATION_STAGE_TAG,
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninPassword2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninPassword2.kt
index 71f1d10137..5c9cefd2db 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninPassword2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninPassword2.kt
@@ -24,17 +24,20 @@ import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.autofill.HintConstants
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.hidePassword
 import im.vector.app.databinding.FragmentLoginSigninPassword2Binding
 import im.vector.app.features.home.AvatarRenderer
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.auth.login.LoginProfileInfo
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.isInvalidPassword
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 import javax.net.ssl.HttpsURLConnection
 
@@ -121,11 +124,11 @@ class LoginFragmentSigninPassword2 @Inject constructor(
         views.passwordField
                 .textChanges()
                 .map { it.isNotEmpty() }
-                .subscribeBy {
+                .onEach {
                     views.passwordFieldTil.error = null
                     views.loginSubmit.isEnabled = it
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun forgetPasswordClicked() {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninUsername2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninUsername2.kt
index 95862a4e90..b90887dba1 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninUsername2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSigninUsername2.kt
@@ -22,13 +22,16 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.autofill.HintConstants
-import com.jakewharton.rxbinding3.widget.textChanges
+import androidx.lifecycle.lifecycleScope
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.databinding.FragmentLoginSigninUsername2Binding
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -83,11 +86,11 @@ class LoginFragmentSigninUsername2 @Inject constructor() : AbstractLoginFragment
         views.loginSubmit.setOnClickListener { submit() }
         views.loginField.textChanges()
                 .map { it.trim().isNotEmpty() }
-                .subscribeBy {
+                .onEach {
                     views.loginFieldTil.error = null
                     views.loginSubmit.isEnabled = it
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun resetViewModel() {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupPassword2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupPassword2.kt
index 28a87a0e8b..806ff0524b 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupPassword2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupPassword2.kt
@@ -23,12 +23,14 @@ import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.autofill.HintConstants
-import com.jakewharton.rxbinding3.widget.textChanges
+import androidx.lifecycle.lifecycleScope
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.hidePassword
 import im.vector.app.databinding.FragmentLoginSignupPassword2Binding
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -87,11 +89,11 @@ class LoginFragmentSignupPassword2 @Inject constructor() : AbstractLoginFragment
     private fun setupSubmitButton() {
         views.loginSubmit.setOnClickListener { submit() }
         views.passwordField.textChanges()
-                .subscribeBy { password ->
+                .onEach { password ->
                     views.passwordFieldTil.error = null
                     views.loginSubmit.isEnabled = password.isNotEmpty()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun resetViewModel() {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupUsername2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupUsername2.kt
index ff6a218796..51044ac153 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupUsername2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentSignupUsername2.kt
@@ -24,14 +24,17 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.autofill.HintConstants
 import androidx.core.view.isVisible
-import com.jakewharton.rxbinding3.widget.textChanges
+import androidx.lifecycle.lifecycleScope
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.databinding.FragmentLoginSignupUsername2Binding
 import im.vector.app.features.login.LoginMode
 import im.vector.app.features.login.SocialLoginButtonsView
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -111,12 +114,12 @@ class LoginFragmentSignupUsername2 @Inject constructor() : AbstractSSOLoginFragm
         views.loginSubmit.setOnClickListener { submit() }
         views.loginField.textChanges()
                 .map { it.trim() }
-                .subscribeBy { text ->
+                .onEach { text ->
                     val isNotEmpty = text.isNotEmpty()
                     views.loginFieldTil.error = null
                     views.loginSubmit.isEnabled = isNotEmpty
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun resetViewModel() {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentToAny2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentToAny2.kt
index a889c870a0..48792da007 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginFragmentToAny2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginFragmentToAny2.kt
@@ -24,7 +24,7 @@ import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.autofill.HintConstants
 import androidx.core.view.isVisible
-import com.jakewharton.rxbinding3.widget.textChanges
+import androidx.lifecycle.lifecycleScope
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.hidePassword
@@ -32,11 +32,14 @@ import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.databinding.FragmentLoginSigninToAny2Binding
 import im.vector.app.features.login.LoginMode
 import im.vector.app.features.login.SocialLoginButtonsView
-import io.reactivex.Observable
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.api.failure.isInvalidPassword
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -136,20 +139,18 @@ class LoginFragmentToAny2 @Inject constructor() : AbstractSSOLoginFragment2<Frag
 
     private fun setupSubmitButton() {
         views.loginSubmit.setOnClickListener { submit() }
-        Observable
-                .combineLatest(
-                        views.loginField.textChanges().map { it.trim().isNotEmpty() },
-                        views.passwordField.textChanges().map { it.isNotEmpty() },
-                        { isLoginNotEmpty, isPasswordNotEmpty ->
-                            isLoginNotEmpty && isPasswordNotEmpty
-                        }
-                )
-                .subscribeBy {
+        combine(
+                views.loginField.textChanges().map { it.trim().isNotEmpty() },
+                views.passwordField.textChanges().map { it.isNotEmpty() }
+        ) { isLoginNotEmpty, isPasswordNotEmpty ->
+            isLoginNotEmpty && isPasswordNotEmpty
+        }
+                .onEach {
                     views.loginFieldTil.error = null
                     views.passwordFieldTil.error = null
                     views.loginSubmit.isEnabled = it
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun forgetPasswordClicked() {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginGenericTextInputFormFragment2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginGenericTextInputFormFragment2.kt
index a87dd6ae40..76af86fda8 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginGenericTextInputFormFragment2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginGenericTextInputFormFragment2.kt
@@ -24,10 +24,10 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.autofill.HintConstants
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.args
 import com.google.i18n.phonenumbers.NumberParseException
 import com.google.i18n.phonenumbers.PhoneNumberUtil
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.isEmail
@@ -36,9 +36,12 @@ import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.databinding.FragmentLoginGenericTextInputForm2Binding
 import im.vector.app.features.login.LoginGenericTextInputFormFragmentArgument
 import im.vector.app.features.login.TextInputFormFragmentMode
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.is401
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -82,10 +85,10 @@ class LoginGenericTextInputFormFragment2 @Inject constructor() : AbstractLoginFr
 
     private fun setupTil() {
         views.loginGenericTextInputFormTextInput.textChanges()
-                .subscribe {
+                .onEach {
                     views.loginGenericTextInputFormTil.error = null
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun setupUi() {
@@ -189,11 +192,11 @@ class LoginGenericTextInputFormFragment2 @Inject constructor() : AbstractLoginFr
     private fun setupSubmitButton() {
         views.loginGenericTextInputFormSubmit.isEnabled = false
         views.loginGenericTextInputFormTextInput.textChanges()
-                .subscribe { text ->
+                .onEach { text ->
                     views.loginGenericTextInputFormSubmit.isEnabled = isInputValid(text)
-                    text?.let { updateSubmitButtons(it) }
+                    updateSubmitButtons(text)
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun updateSubmitButtons(text: CharSequence) {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginResetPasswordFragment2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginResetPasswordFragment2.kt
index 6d6ddbc470..c00ed7275c 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginResetPasswordFragment2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginResetPasswordFragment2.kt
@@ -23,8 +23,8 @@ import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import androidx.autofill.HintConstants
+import androidx.lifecycle.lifecycleScope
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.extensions.hidePassword
@@ -32,8 +32,11 @@ import im.vector.app.core.extensions.isEmail
 import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.core.utils.autoResetTextInputLayoutErrors
 import im.vector.app.databinding.FragmentLoginResetPassword2Binding
-import io.reactivex.Observable
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 /**
@@ -78,19 +81,16 @@ class LoginResetPasswordFragment2 @Inject constructor() : AbstractLoginFragment2
 
     private fun setupSubmitButton() {
         views.resetPasswordSubmit.setOnClickListener { submit() }
-
-        Observable
-                .combineLatest(
-                        views.resetPasswordEmail.textChanges().map { it.isEmail() },
-                        views.passwordField.textChanges().map { it.isNotEmpty() },
-                        { isEmail, isPasswordNotEmpty ->
-                            isEmail && isPasswordNotEmpty
-                        }
-                )
-                .subscribeBy {
+        combine(
+                views.resetPasswordEmail.textChanges().map { it.isEmail() },
+                views.passwordField.textChanges().map { it.isNotEmpty() }
+        ) { isEmail, isPasswordNotEmpty ->
+            isEmail && isPasswordNotEmpty
+        }
+                .onEach {
                     views.resetPasswordSubmit.isEnabled = it
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun submit() {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginServerUrlFormFragment2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginServerUrlFormFragment2.kt
index 6a67f0513c..0732d176ac 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginServerUrlFormFragment2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginServerUrlFormFragment2.kt
@@ -24,15 +24,18 @@ import android.view.ViewGroup
 import android.view.inputmethod.EditorInfo
 import android.widget.ArrayAdapter
 import androidx.core.view.isInvisible
+import androidx.lifecycle.lifecycleScope
 import com.google.android.material.textfield.TextInputLayout
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.BuildConfig
 import im.vector.app.R
 import im.vector.app.core.extensions.hideKeyboard
 import im.vector.app.core.utils.ensureProtocol
 import im.vector.app.databinding.FragmentLoginServerUrlForm2Binding
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
+import reactivecircus.flowbinding.android.widget.textChanges
 import java.net.UnknownHostException
 import javax.inject.Inject
 import javax.net.ssl.HttpsURLConnection
@@ -60,11 +63,11 @@ class LoginServerUrlFormFragment2 @Inject constructor() : AbstractLoginFragment2
 
     private fun setupHomeServerField() {
         views.loginServerUrlFormHomeServerUrl.textChanges()
-                .subscribe {
+                .onEach {
                     views.loginServerUrlFormHomeServerUrlTil.error = null
                     views.loginServerUrlFormSubmit.isEnabled = it.isNotBlank()
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.loginServerUrlFormHomeServerUrl.setOnEditorActionListener { _, actionId, _ ->
             if (actionId == EditorInfo.IME_ACTION_DONE) {
diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt
index 09ca979c6c..b73988126b 100644
--- a/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt
@@ -18,17 +18,16 @@ package im.vector.app.features.login2
 
 import android.content.Context
 import android.net.Uri
-import androidx.fragment.app.FragmentActivity
 import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.tryAsync
@@ -72,10 +71,12 @@ class LoginViewModel2 @AssistedInject constructor(
 ) : VectorViewModel<LoginViewState2, LoginAction2, LoginViewEvents2>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: LoginViewState2): LoginViewModel2
+    interface Factory : MavericksAssistedViewModelFactory<LoginViewModel2, LoginViewState2> {
+        override fun create(initialState: LoginViewState2): LoginViewModel2
     }
 
+    companion object : MavericksViewModelFactory<LoginViewModel2, LoginViewState2> by hiltMavericksViewModelFactory()
+
     init {
         getKnownCustomHomeServersUrls()
     }
@@ -86,18 +87,6 @@ class LoginViewModel2 @AssistedInject constructor(
         }
     }
 
-    companion object : MavericksViewModelFactory<LoginViewModel2, LoginViewState2> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: LoginViewState2): LoginViewModel2? {
-            return when (val activity: FragmentActivity = (viewModelContext as ActivityViewModelContext).activity()) {
-                is LoginActivity2 -> activity.loginViewModelFactory.create(state)
-                // TODO is SoftLogoutActivity -> activity.loginViewModelFactory.create(state)
-                else              -> error("Invalid Activity")
-            }
-        }
-    }
-
     // Store the last action, to redo it after user has trusted the untrusted certificate
     private var lastAction: LoginAction2? = null
     private var currentHomeServerConnectionConfig: HomeServerConnectionConfig? = null
@@ -558,7 +547,7 @@ class LoginViewModel2 @AssistedInject constructor(
                     safeLoginWizard.login(
                             login = login,
                             password = password,
-                            deviceName = stringProvider.getString(R.string.login_default_session_public_name)
+                            initialDeviceName = stringProvider.getString(R.string.login_default_session_public_name)
                     )
                 } catch (failure: Throwable) {
                     _viewEvents.post(LoginViewEvents2.Failure(failure))
diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt
index 5668214b50..efa4bd29c6 100644
--- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt
@@ -49,7 +49,6 @@ import javax.inject.Inject
  * - the account has been created and we propose the user to set an avatar and a display name
  */
 class AccountCreatedFragment @Inject constructor(
-        val accountCreatedViewModelFactory: AccountCreatedViewModel.Factory,
         private val avatarRenderer: AvatarRenderer,
         private val dateFormatter: VectorDateFormatter,
         private val matrixItemColorProvider: MatrixItemColorProvider,
diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt
index 34957dd47b..568cdab119 100644
--- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt
@@ -16,13 +16,12 @@
 
 package im.vector.app.features.login2.created
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
@@ -40,18 +39,11 @@ class AccountCreatedViewModel @AssistedInject constructor(
 ) : VectorViewModel<AccountCreatedViewState, AccountCreatedAction, AccountCreatedViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: AccountCreatedViewState): AccountCreatedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<AccountCreatedViewModel, AccountCreatedViewState> {
+        override fun create(initialState: AccountCreatedViewState): AccountCreatedViewModel
     }
 
-    companion object : MavericksViewModelFactory<AccountCreatedViewModel, AccountCreatedViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: AccountCreatedViewState): AccountCreatedViewModel? {
-            val fragment: AccountCreatedFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.accountCreatedViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<AccountCreatedViewModel, AccountCreatedViewState> by hiltMavericksViewModelFactory()
 
     init {
         setState {
diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt
index aadabcb1b4..029234a66d 100644
--- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt
@@ -28,8 +28,8 @@ import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetMatrixToCardBinding
@@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.permalinks.PermalinkData
 import javax.inject.Inject
 import kotlin.reflect.KClass
 
+@AndroidEntryPoint
 class MatrixToBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetMatrixToCardBinding>() {
 
@@ -49,13 +50,6 @@ class MatrixToBottomSheet :
 
     @Inject lateinit var avatarRenderer: AvatarRenderer
 
-    @Inject
-    lateinit var matrixToBottomSheetViewModelFactory: MatrixToBottomSheetViewModel.Factory
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     var interactionListener: InteractionListener? = null
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetMatrixToCardBinding {
diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt
index 327485a3b0..e741f6fb39 100644
--- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt
@@ -16,18 +16,17 @@
 
 package im.vector.app.features.matrixto
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
@@ -54,10 +53,12 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
     VectorViewModel<MatrixToBottomSheetState, MatrixToAction, MatrixToViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: MatrixToBottomSheetState): MatrixToBottomSheetViewModel
+    interface Factory : MavericksAssistedViewModelFactory<MatrixToBottomSheetViewModel, MatrixToBottomSheetState> {
+        override fun create(initialState: MatrixToBottomSheetState): MatrixToBottomSheetViewModel
     }
 
+    companion object : MavericksViewModelFactory<MatrixToBottomSheetViewModel, MatrixToBottomSheetState> by hiltMavericksViewModelFactory()
+
     init {
         when (initialState.linkType) {
             is PermalinkData.RoomLink     -> {
@@ -245,14 +246,6 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
         return session.peekRoom(roomIdOrAlias)
     }
 
-    companion object : MavericksViewModelFactory<MatrixToBottomSheetViewModel, MatrixToBottomSheetState> {
-        override fun create(viewModelContext: ViewModelContext, state: MatrixToBottomSheetState): MatrixToBottomSheetViewModel? {
-            val fragment: MatrixToBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-
-            return fragment.matrixToBottomSheetViewModelFactory.create(state)
-        }
-    }
-
     override fun handle(action: MatrixToAction) {
         when (action) {
             is MatrixToAction.StartChattingWithUser -> handleStartChatting(action)
diff --git a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt
index 28d16adcbb..84454ee509 100644
--- a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt
@@ -20,8 +20,8 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import androidx.core.net.toUri
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityBigImageViewerBinding
 import javax.inject.Inject
@@ -29,15 +29,12 @@ import javax.inject.Inject
 /**
  * Simple Activity to display an avatar in fullscreen
  */
+@AndroidEntryPoint
 class BigImageViewerActivity : VectorBaseActivity<ActivityBigImageViewerBinding>() {
     @Inject lateinit var sessionHolder: ActiveSessionHolder
 
     override fun getBinding() = ActivityBigImageViewerBinding.inflate(layoutInflater)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
diff --git a/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt
index bc3acf3eec..103511bad5 100644
--- a/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt
@@ -30,12 +30,9 @@ import androidx.core.view.isInvisible
 import androidx.core.view.isVisible
 import androidx.lifecycle.lifecycleScope
 import androidx.transition.Transition
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.DaggerScreenComponent
-import im.vector.app.core.di.HasVectorInjector
-import im.vector.app.core.di.ScreenComponent
-import im.vector.app.core.di.VectorComponent
 import im.vector.app.core.intent.getMimeTypeFromUri
 import im.vector.app.core.utils.shareMedia
 import im.vector.app.features.themes.ActivityOtherThemes
@@ -48,8 +45,8 @@ import kotlinx.coroutines.withContext
 import kotlinx.parcelize.Parcelize
 import timber.log.Timber
 import javax.inject.Inject
-import kotlin.system.measureTimeMillis
 
+@AndroidEntryPoint
 class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmentProvider.InteractionListener {
 
     @Parcelize
@@ -61,15 +58,11 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmen
 
     @Inject
     lateinit var sessionHolder: ActiveSessionHolder
-
     @Inject
     lateinit var dataSourceFactory: AttachmentProviderFactory
-
     @Inject
     lateinit var imageContentRenderer: ImageContentRenderer
 
-    private lateinit var screenComponent: ScreenComponent
-
     private var initialIndex = 0
     private var isAnimatingOut = false
 
@@ -78,12 +71,6 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmen
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         Timber.i("onCreate Activity ${javaClass.simpleName}")
-        val vectorComponent = getVectorComponent()
-        screenComponent = DaggerScreenComponent.factory().create(vectorComponent, this)
-        val timeForInjection = measureTimeMillis {
-            screenComponent.inject(this)
-        }
-        Timber.v("Injecting dependencies into ${javaClass.simpleName} took $timeForInjection ms")
         ThemeUtils.setActivityTheme(this, getOtherThemes())
 
         val args = args() ?: throw IllegalArgumentException("Missing arguments")
@@ -220,10 +207,6 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), BaseAttachmen
 
     private fun args() = intent.getParcelableExtra<Args>(EXTRA_ARGS)
 
-    private fun getVectorComponent(): VectorComponent {
-        return (application as HasVectorInjector).injector()
-    }
-
     private fun scheduleStartPostponedTransition(sharedElement: View) {
         sharedElement.viewTreeObserver.addOnPreDrawListener(
                 object : ViewTreeObserver.OnPreDrawListener {
diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
index 9a28c1a080..56908bf8ec 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
@@ -64,6 +64,8 @@ import im.vector.app.features.media.VectorAttachmentViewerActivity
 import im.vector.app.features.pin.PinActivity
 import im.vector.app.features.pin.PinArgs
 import im.vector.app.features.pin.PinMode
+import im.vector.app.features.poll.create.CreatePollActivity
+import im.vector.app.features.poll.create.CreatePollArgs
 import im.vector.app.features.roomdirectory.RoomDirectoryActivity
 import im.vector.app.features.roomdirectory.RoomDirectoryData
 import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
@@ -498,6 +500,14 @@ class DefaultNavigator @Inject constructor(
         context.startActivity(intent)
     }
 
+    override fun openCreatePoll(context: Context, roomId: String) {
+        val intent = CreatePollActivity.getIntent(
+                context,
+                CreatePollArgs(roomId = roomId)
+        )
+        context.startActivity(intent)
+    }
+
     private fun startActivity(context: Context, intent: Intent, buildTask: Boolean) {
         if (buildTask) {
             val stackBuilder = TaskStackBuilder.create(context)
diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
index 1bfef4a25a..d12e5a53e0 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
@@ -140,4 +140,6 @@ interface Navigator {
     fun openDevTools(context: Context, roomId: String)
 
     fun openCallTransfer(context: Context, callId: String)
+
+    fun openCreatePoll(context: Context, roomId: String)
 }
diff --git a/vector/src/main/java/im/vector/app/features/notifications/InviteNotifiableEvent.kt b/vector/src/main/java/im/vector/app/features/notifications/InviteNotifiableEvent.kt
index 61fd5c677a..832f97bc4e 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/InviteNotifiableEvent.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/InviteNotifiableEvent.kt
@@ -15,22 +15,18 @@
  */
 package im.vector.app.features.notifications
 
-import androidx.core.app.NotificationCompat
-
 data class InviteNotifiableEvent(
-        override var matrixID: String?,
+        val matrixID: String?,
         override val eventId: String,
         override val editedEventId: String?,
-        var roomId: String,
-        override var noisy: Boolean,
-        override val title: String,
-        override val description: String,
-        override val type: String?,
-        override val timestamp: Long,
-        override var soundName: String?,
-        override var isPushGatewayEvent: Boolean = false) : NotifiableEvent {
-
-    override var hasBeenDisplayed: Boolean = false
-    override var isRedacted: Boolean = false
-    override var lockScreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
-}
+        override val canBeReplaced: Boolean,
+        val roomId: String,
+        val roomName: String?,
+        val noisy: Boolean,
+        val title: String,
+        val description: String,
+        val type: String?,
+        val timestamp: Long,
+        val soundName: String?,
+        override val isRedacted: Boolean = false
+) : NotifiableEvent
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEvent.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEvent.kt
index a4f099b905..52d8119cbb 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEvent.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEvent.kt
@@ -20,24 +20,11 @@ import java.io.Serializable
 /**
  * Parent interface for all events which can be displayed as a Notification
  */
-interface NotifiableEvent : Serializable {
-    var matrixID: String?
+sealed interface NotifiableEvent : Serializable {
     val eventId: String
     val editedEventId: String?
-    var noisy: Boolean
-    val title: String
-    val description: String?
-    val type: String?
-    val timestamp: Long
-
-    // NotificationCompat.VISIBILITY_PUBLIC , VISIBILITY_PRIVATE , VISIBILITY_SECRET
-    var lockScreenVisibility: Int
-
-    // Compat: Only for android <7, for newer version the sound is defined in the channel
-    var soundName: String?
-    var hasBeenDisplayed: Boolean
-    var isRedacted: Boolean
 
     // Used to know if event should be replaced with the one coming from eventstream
-    var isPushGatewayEvent: Boolean
+    val canBeReplaced: Boolean
+    val isRedacted: Boolean
 }
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt
new file mode 100644
index 0000000000..3d10d74fe3
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventProcessor.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import im.vector.app.features.invite.AutoAcceptInvites
+import im.vector.app.features.notifications.ProcessedEvent.Type.KEEP
+import im.vector.app.features.notifications.ProcessedEvent.Type.REMOVE
+import org.matrix.android.sdk.api.session.events.model.EventType
+import javax.inject.Inject
+
+private typealias ProcessedEvents = List<ProcessedEvent<NotifiableEvent>>
+
+class NotifiableEventProcessor @Inject constructor(
+        private val outdatedDetector: OutdatedEventDetector,
+        private val autoAcceptInvites: AutoAcceptInvites
+) {
+
+    fun process(queuedEvents: List<NotifiableEvent>, currentRoomId: String?, renderedEvents: ProcessedEvents): ProcessedEvents {
+        val processedEvents = queuedEvents.map {
+            val type = when (it) {
+                is InviteNotifiableEvent  -> if (autoAcceptInvites.hideInvites) REMOVE else KEEP
+                is NotifiableMessageEvent -> if (shouldIgnoreMessageEventInRoom(currentRoomId, it.roomId) || outdatedDetector.isMessageOutdated(it)) {
+                    REMOVE
+                } else KEEP
+                is SimpleNotifiableEvent  -> when (it.type) {
+                    EventType.REDACTION -> REMOVE
+                    else                -> KEEP
+                }
+            }
+            ProcessedEvent(type, it)
+        }
+
+        val removedEventsDiff = renderedEvents.filter { renderedEvent ->
+            queuedEvents.none { it.eventId == renderedEvent.event.eventId }
+        }.map { ProcessedEvent(REMOVE, it.event) }
+
+        return removedEventsDiff + processedEvents
+    }
+
+    private fun shouldIgnoreMessageEventInRoom(currentRoomId: String?, roomId: String?): Boolean {
+        return currentRoomId != null && roomId == currentRoomId
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt
index 63c296f418..87b31fa92a 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt
@@ -15,9 +15,10 @@
  */
 package im.vector.app.features.notifications
 
-import androidx.core.app.NotificationCompat
+import android.net.Uri
 import im.vector.app.BuildConfig
 import im.vector.app.R
+import im.vector.app.core.extensions.takeAs
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.displayname.getBestName
 import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
@@ -29,12 +30,15 @@ import org.matrix.android.sdk.api.session.crypto.MXCryptoError
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.isEdition
+import org.matrix.android.sdk.api.session.events.model.isImageMessage
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
 import org.matrix.android.sdk.api.session.room.sender.SenderInfo
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.session.room.timeline.getEditedEventId
+import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
 import org.matrix.android.sdk.api.util.toMatrixItem
 import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
 import timber.log.Timber
@@ -50,25 +54,24 @@ import javax.inject.Inject
 class NotifiableEventResolver @Inject constructor(
         private val stringProvider: StringProvider,
         private val noticeEventFormatter: NoticeEventFormatter,
-        private val displayableEventFormatter: DisplayableEventFormatter) {
+        private val displayableEventFormatter: DisplayableEventFormatter
+) {
 
     // private val eventDisplay = RiotEventDisplay(context)
 
-    fun resolveEvent(event: Event/*, roomState: RoomState?, bingRule: PushRule?*/, session: Session): NotifiableEvent? {
+    suspend fun resolveEvent(event: Event/*, roomState: RoomState?, bingRule: PushRule?*/, session: Session, isNoisy: Boolean): NotifiableEvent? {
         val roomID = event.roomId ?: return null
         val eventId = event.eventId ?: return null
         if (event.getClearType() == EventType.STATE_ROOM_MEMBER) {
-            return resolveStateRoomEvent(event, session)
+            return resolveStateRoomEvent(event, session, canBeReplaced = false, isNoisy = isNoisy)
         }
         val timelineEvent = session.getRoom(roomID)?.getTimeLineEvent(eventId) ?: return null
         when (event.getClearType()) {
             EventType.MESSAGE   -> {
-                return resolveMessageEvent(timelineEvent, session)
+                return resolveMessageEvent(timelineEvent, session, canBeReplaced = false, isNoisy = isNoisy)
             }
             EventType.ENCRYPTED -> {
-                val messageEvent = resolveMessageEvent(timelineEvent, session)
-                messageEvent?.lockScreenVisibility = NotificationCompat.VISIBILITY_PRIVATE
-                return messageEvent
+                return resolveMessageEvent(timelineEvent, session, canBeReplaced = false, isNoisy = isNoisy)
             }
             else                -> {
                 // If the event can be displayed, display it as is
@@ -85,12 +88,14 @@ class NotifiableEventResolver @Inject constructor(
                         description = bodyPreview,
                         title = stringProvider.getString(R.string.notification_unknown_new_event),
                         soundName = null,
-                        type = event.type)
+                        type = event.type,
+                        canBeReplaced = false
+                )
             }
         }
     }
 
-    fun resolveInMemoryEvent(session: Session, event: Event): NotifiableEvent? {
+    suspend fun resolveInMemoryEvent(session: Session, event: Event, canBeReplaced: Boolean): NotifiableEvent? {
         if (event.getClearType() != EventType.MESSAGE) return null
 
         // Ignore message edition
@@ -114,24 +119,14 @@ class NotifiableEventResolver @Inject constructor(
                             avatarUrl = user.avatarUrl
                     )
             )
-
-            val notifiableEvent = resolveMessageEvent(timelineEvent, session)
-
-            if (notifiableEvent == null) {
-                Timber.d("## Failed to resolve event")
-                // TODO
-                null
-            } else {
-                notifiableEvent.noisy = !notificationAction.soundName.isNullOrBlank()
-                notifiableEvent
-            }
+            resolveMessageEvent(timelineEvent, session, canBeReplaced = canBeReplaced, isNoisy = !notificationAction.soundName.isNullOrBlank())
         } else {
             Timber.d("Matched push rule is set to not notify")
             null
         }
     }
 
-    private fun resolveMessageEvent(event: TimelineEvent, session: Session): NotifiableEvent? {
+    private suspend fun resolveMessageEvent(event: TimelineEvent, session: Session, canBeReplaced: Boolean, isNoisy: Boolean): NotifiableEvent {
         // The event only contains an eventId, and roomId (type is m.room.*) , we need to get the displayable content (names, avatar, text, etc...)
         val room = session.getRoom(event.root.roomId!! /*roomID cannot be null*/)
 
@@ -142,19 +137,20 @@ class NotifiableEventResolver @Inject constructor(
             val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
             val senderDisplayName = event.senderInfo.disambiguatedDisplayName
 
-            val notifiableEvent = NotifiableMessageEvent(
+            return NotifiableMessageEvent(
                     eventId = event.root.eventId!!,
                     editedEventId = event.getEditedEventId(),
+                    canBeReplaced = canBeReplaced,
                     timestamp = event.root.originServerTs ?: 0,
-                    noisy = false, // will be updated
+                    noisy = isNoisy,
                     senderName = senderDisplayName,
                     senderId = event.root.senderId,
                     body = body.toString(),
+                    imageUri = event.fetchImageIfPresent(session),
                     roomId = event.root.roomId!!,
-                    roomName = roomName)
-
-            notifiableEvent.matrixID = session.myUserId
-            return notifiableEvent
+                    roomName = roomName,
+                    matrixID = session.myUserId
+            )
         } else {
             if (event.root.isEncrypted() && event.root.mxDecryptionResult == null) {
                 // TODO use a global event decryptor? attache to session and that listen to new sessionId?
@@ -175,57 +171,77 @@ class NotifiableEventResolver @Inject constructor(
             val roomName = room.roomSummary()?.displayName ?: ""
             val senderDisplayName = event.senderInfo.disambiguatedDisplayName
 
-            val notifiableEvent = NotifiableMessageEvent(
+            return NotifiableMessageEvent(
                     eventId = event.root.eventId!!,
                     editedEventId = event.getEditedEventId(),
+                    canBeReplaced = canBeReplaced,
                     timestamp = event.root.originServerTs ?: 0,
-                    noisy = false, // will be updated
+                    noisy = isNoisy,
                     senderName = senderDisplayName,
                     senderId = event.root.senderId,
                     body = body,
+                    imageUri = event.fetchImageIfPresent(session),
                     roomId = event.root.roomId!!,
                     roomName = roomName,
-                    roomIsDirect = room.roomSummary()?.isDirect ?: false)
-
-            notifiableEvent.matrixID = session.myUserId
-            notifiableEvent.soundName = null
-
-            // Get the avatars URL
-            notifiableEvent.roomAvatarPath = session.contentUrlResolver()
-                    .resolveThumbnail(room.roomSummary()?.avatarUrl,
-                            250,
-                            250,
-                            ContentUrlResolver.ThumbnailMethod.SCALE)
-
-            notifiableEvent.senderAvatarPath = session.contentUrlResolver()
-                    .resolveThumbnail(event.senderInfo.avatarUrl,
-                            250,
-                            250,
-                            ContentUrlResolver.ThumbnailMethod.SCALE)
-
-            return notifiableEvent
+                    roomIsDirect = room.roomSummary()?.isDirect ?: false,
+                    roomAvatarPath = session.contentUrlResolver()
+                            .resolveThumbnail(room.roomSummary()?.avatarUrl,
+                                    250,
+                                    250,
+                                    ContentUrlResolver.ThumbnailMethod.SCALE),
+                    senderAvatarPath = session.contentUrlResolver()
+                            .resolveThumbnail(event.senderInfo.avatarUrl,
+                                    250,
+                                    250,
+                                    ContentUrlResolver.ThumbnailMethod.SCALE),
+                    matrixID = session.myUserId,
+                    soundName = null
+            )
         }
     }
 
-    private fun resolveStateRoomEvent(event: Event, session: Session): NotifiableEvent? {
+    private suspend fun TimelineEvent.fetchImageIfPresent(session: Session): Uri? {
+        return when {
+            root.isEncrypted() && root.mxDecryptionResult == null -> null
+            root.isImageMessage()                                 -> downloadAndExportImage(session)
+            else                                                  -> null
+        }
+    }
+
+    private suspend fun TimelineEvent.downloadAndExportImage(session: Session): Uri? {
+        return kotlin.runCatching {
+            getLastMessageContent()?.takeAs<MessageWithAttachmentContent>()?.let { imageMessage ->
+                val fileService = session.fileService()
+                fileService.downloadFile(imageMessage)
+                fileService.getTemporarySharableURI(imageMessage)
+            }
+        }.onFailure {
+            Timber.e(it, "Failed to download and export image for notification")
+        }.getOrNull()
+    }
+
+    private fun resolveStateRoomEvent(event: Event, session: Session, canBeReplaced: Boolean, isNoisy: Boolean): NotifiableEvent? {
         val content = event.content?.toModel<RoomMemberContent>() ?: return null
         val roomId = event.roomId ?: return null
         val dName = event.senderId?.let { session.getRoomMember(it, roomId)?.displayName }
         if (Membership.INVITE == content.membership) {
-            val body = noticeEventFormatter.format(event, dName, isDm = session.getRoomSummary(roomId)?.isDirect.orFalse())
+            val roomSummary = session.getRoomSummary(roomId)
+            val body = noticeEventFormatter.format(event, dName, isDm = roomSummary?.isDirect.orFalse())
                     ?: stringProvider.getString(R.string.notification_new_invitation)
             return InviteNotifiableEvent(
                     session.myUserId,
                     eventId = event.eventId!!,
                     editedEventId = null,
+                    canBeReplaced = canBeReplaced,
                     roomId = roomId,
+                    roomName = roomSummary?.displayName,
                     timestamp = event.originServerTs ?: 0,
-                    noisy = false, // will be set later
+                    noisy = isNoisy,
                     title = stringProvider.getString(R.string.notification_new_invitation),
                     description = body.toString(),
                     soundName = null, // will be set later
-                    type = event.getClearType(),
-                    isPushGatewayEvent = false)
+                    type = event.getClearType()
+            )
         } else {
             Timber.e("## unsupported notifiable event for eventId [${event.eventId}]")
             if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableMessageEvent.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableMessageEvent.kt
index fb9ca8d23c..35718666b0 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableMessageEvent.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableMessageEvent.kt
@@ -15,43 +15,33 @@
  */
 package im.vector.app.features.notifications
 
-import androidx.core.app.NotificationCompat
+import android.net.Uri
 import org.matrix.android.sdk.api.session.events.model.EventType
 
 data class NotifiableMessageEvent(
         override val eventId: String,
         override val editedEventId: String?,
-        override var noisy: Boolean,
-        override val timestamp: Long,
-        var senderName: String?,
-        var senderId: String?,
-        var body: String?,
-        var roomId: String,
-        var roomName: String?,
-        var roomIsDirect: Boolean = false
+        override val canBeReplaced: Boolean,
+        val noisy: Boolean,
+        val timestamp: Long,
+        val senderName: String?,
+        val senderId: String?,
+        val body: String?,
+        val imageUri: Uri?,
+        val roomId: String,
+        val roomName: String?,
+        val roomIsDirect: Boolean = false,
+        val roomAvatarPath: String? = null,
+        val senderAvatarPath: String? = null,
+        val matrixID: String? = null,
+        val soundName: String? = null,
+        // This is used for >N notification, as the result of a smart reply
+        val outGoingMessage: Boolean = false,
+        val outGoingMessageFailed: Boolean = false,
+        override val isRedacted: Boolean = false
 ) : NotifiableEvent {
 
-    override var matrixID: String? = null
-    override var soundName: String? = null
-    override var lockScreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
-    override var hasBeenDisplayed: Boolean = false
-    override var isRedacted: Boolean = false
-
-    var roomAvatarPath: String? = null
-    var senderAvatarPath: String? = null
-
-    override var isPushGatewayEvent: Boolean = false
-
-    override val type: String
-        get() = EventType.MESSAGE
-
-    override val description: String?
-        get() = body ?: ""
-
-    override val title: String
-        get() = senderName ?: ""
-
-    // This is used for >N notification, as the result of a smart reply
-    var outGoingMessage = false
-    var outGoingMessageFailed = false
+    val type: String = EventType.MESSAGE
+    val description: String = body ?: ""
+    val title: String = senderName ?: ""
 }
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt
index 2c4cdab25e..b1905059a1 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt
@@ -20,9 +20,9 @@ import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
 import androidx.core.app.RemoteInput
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.extensions.vectorComponent
 import im.vector.app.features.session.coroutineScope
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.extensions.tryOrNull
@@ -36,6 +36,7 @@ import javax.inject.Inject
 /**
  * Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.)
  */
+@AndroidEntryPoint
 class NotificationBroadcastReceiver : BroadcastReceiver() {
 
     @Inject lateinit var notificationDrawerManager: NotificationDrawerManager
@@ -44,31 +45,30 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
     override fun onReceive(context: Context?, intent: Intent?) {
         if (intent == null || context == null) return
         Timber.v("NotificationBroadcastReceiver received : $intent")
-        context.vectorComponent().inject(this)
         when (intent.action) {
             NotificationUtils.SMART_REPLY_ACTION        ->
                 handleSmartReply(intent, context)
             NotificationUtils.DISMISS_ROOM_NOTIF_ACTION ->
-                intent.getStringExtra(KEY_ROOM_ID)?.let {
-                    notificationDrawerManager.clearMessageEventOfRoom(it)
+                intent.getStringExtra(KEY_ROOM_ID)?.let { roomId ->
+                    notificationDrawerManager.updateEvents { it.clearMessagesForRoom(roomId) }
                 }
             NotificationUtils.DISMISS_SUMMARY_ACTION    ->
                 notificationDrawerManager.clearAllEvents()
             NotificationUtils.MARK_ROOM_READ_ACTION     ->
-                intent.getStringExtra(KEY_ROOM_ID)?.let {
-                    notificationDrawerManager.clearMessageEventOfRoom(it)
-                    handleMarkAsRead(it)
+                intent.getStringExtra(KEY_ROOM_ID)?.let { roomId ->
+                    notificationDrawerManager.updateEvents { it.clearMessagesForRoom(roomId) }
+                    handleMarkAsRead(roomId)
                 }
             NotificationUtils.JOIN_ACTION               -> {
-                intent.getStringExtra(KEY_ROOM_ID)?.let {
-                    notificationDrawerManager.clearMemberShipNotificationForRoom(it)
-                    handleJoinRoom(it)
+                intent.getStringExtra(KEY_ROOM_ID)?.let { roomId ->
+                    notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(roomId) }
+                    handleJoinRoom(roomId)
                 }
             }
             NotificationUtils.REJECT_ACTION             -> {
-                intent.getStringExtra(KEY_ROOM_ID)?.let {
-                    notificationDrawerManager.clearMemberShipNotificationForRoom(it)
-                    handleRejectRoom(it)
+                intent.getStringExtra(KEY_ROOM_ID)?.let { roomId ->
+                    notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(roomId) }
+                    handleRejectRoom(roomId)
                 }
             }
         }
@@ -130,22 +130,23 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
 
         val notifiableMessageEvent = NotifiableMessageEvent(
                 // Generate a Fake event id
-                UUID.randomUUID().toString(),
-                null,
-                false,
-                System.currentTimeMillis(),
-                session.getRoomMember(session.myUserId, room.roomId)?.displayName
+                eventId = UUID.randomUUID().toString(),
+                editedEventId = null,
+                noisy = false,
+                timestamp = System.currentTimeMillis(),
+                senderName = session.getRoomMember(session.myUserId, room.roomId)?.displayName
                         ?: context?.getString(R.string.notification_sender_me),
-                session.myUserId,
-                message,
-                room.roomId,
-                room.roomSummary()?.displayName ?: room.roomId,
-                room.roomSummary()?.isDirect == true
+                senderId = session.myUserId,
+                body = message,
+                imageUri = null,
+                roomId = room.roomId,
+                roomName = room.roomSummary()?.displayName ?: room.roomId,
+                roomIsDirect = room.roomSummary()?.isDirect == true,
+                outGoingMessage = true,
+                canBeReplaced = false
         )
-        notifiableMessageEvent.outGoingMessage = true
 
-        notificationDrawerManager.onNotifiableEventReceived(notifiableMessageEvent)
-        notificationDrawerManager.refreshNotificationDrawer()
+        notificationDrawerManager.updateEvents { it.onNotifiableEventReceived(notifiableMessageEvent) }
 
         /*
         // TODO Error cannot be managed the same way than in Riot
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt
new file mode 100644
index 0000000000..680ff32a52
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import android.app.Notification
+import android.content.Context
+import androidx.core.app.NotificationManagerCompat
+import timber.log.Timber
+import javax.inject.Inject
+
+class NotificationDisplayer @Inject constructor(context: Context) {
+
+    private val notificationManager = NotificationManagerCompat.from(context)
+
+    fun showNotificationMessage(tag: String?, id: Int, notification: Notification) {
+        notificationManager.notify(tag, id, notification)
+    }
+
+    fun cancelNotificationMessage(tag: String?, id: Int) {
+        notificationManager.cancel(tag, id)
+    }
+
+    fun cancelAllNotifications() {
+        // Keep this try catch (reported by GA)
+        try {
+            notificationManager.cancelAll()
+        } catch (e: Exception) {
+            Timber.e(e, "## cancelAllNotifications() failed")
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt
index 0e5247fe2f..e86a65c3fe 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt
@@ -16,26 +16,15 @@
 package im.vector.app.features.notifications
 
 import android.content.Context
-import android.graphics.Bitmap
-import android.os.Build
 import android.os.Handler
 import android.os.HandlerThread
 import androidx.annotation.WorkerThread
-import androidx.core.app.NotificationCompat
-import androidx.core.app.Person
-import androidx.core.content.pm.ShortcutInfoCompat
-import androidx.core.content.pm.ShortcutManagerCompat
-import androidx.core.graphics.drawable.IconCompat
 import im.vector.app.ActiveSessionDataSource
 import im.vector.app.BuildConfig
 import im.vector.app.R
-import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.utils.FirstThrottler
 import im.vector.app.features.displayname.getBestName
-import im.vector.app.features.home.room.detail.RoomDetailActivity
-import im.vector.app.features.invite.AutoAcceptInvites
 import im.vector.app.features.settings.VectorPreferences
-import me.gujun.android.span.span
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.content.ContentUrlResolver
 import org.matrix.android.sdk.api.util.toMatrixItem
@@ -52,14 +41,11 @@ import javax.inject.Singleton
  */
 @Singleton
 class NotificationDrawerManager @Inject constructor(private val context: Context,
-                                                    private val notificationUtils: NotificationUtils,
+                                                    private val notificationDisplayer: NotificationDisplayer,
                                                     private val vectorPreferences: VectorPreferences,
-                                                    private val stringProvider: StringProvider,
                                                     private val activeSessionDataSource: ActiveSessionDataSource,
-                                                    private val iconLoader: IconLoader,
-                                                    private val bitmapLoader: BitmapLoader,
-                                                    private val outdatedDetector: OutdatedEventDetector?,
-                                                    private val autoAcceptInvites: AutoAcceptInvites) {
+                                                    private val notifiableEventProcessor: NotifiableEventProcessor,
+                                                    private val notificationRenderer: NotificationRenderer) {
 
     private val handlerThread: HandlerThread = HandlerThread("NotificationDrawerManager", Thread.MIN_PRIORITY)
     private var backgroundHandler: Handler
@@ -69,13 +55,23 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
         backgroundHandler = Handler(handlerThread.looper)
     }
 
-    // The first time the notification drawer is refreshed, we force re-render of all notifications
-    private var firstTime = true
-
-    private val eventList = loadEventInfo()
+    /**
+     * The notifiable events to render
+     * this is our source of truth for notifications, any changes to this list will be rendered as notifications
+     * when events are removed the previously rendered notifications will be cancelled
+     * when adding or updating, the notifications will be notified
+     *
+     * Events are unique by their properties, we should be careful not to insert multiple events with the same event-id
+     */
+    private val queuedEvents = loadEventInfo()
 
+    /**
+     * The last known rendered notifiable events
+     * we keep track of them in order to know which events have been removed from the eventList
+     * allowing us to cancel any notifications previous displayed by now removed events
+     */
+    private var renderedEvents = emptyList<ProcessedEvent<NotifiableEvent>>()
     private val avatarSize = context.resources.getDimensionPixelSize(R.dimen.profile_avatar_size)
-
     private var currentRoomId: String? = null
 
     // TODO Multi-session: this will have to be improved
@@ -97,7 +93,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
     #refreshNotificationDrawer() is called.
     Events might be grouped and there might not be one notification per event!
      */
-    fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
+    fun NotificationEventQueue.onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
         if (!vectorPreferences.areNotificationEnabledForDevice()) {
             Timber.i("Notification are disabled for this device")
             return
@@ -107,93 +103,17 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
         if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
             Timber.d("onNotifiableEventReceived(): $notifiableEvent")
         } else {
-            Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.isPushGatewayEvent}")
+            Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}")
         }
-        synchronized(eventList) {
-            val existing = eventList.firstOrNull { it.eventId == notifiableEvent.eventId }
-            if (existing != null) {
-                if (existing.isPushGatewayEvent) {
-                    // Use the event coming from the event stream as it may contains more info than
-                    // the fcm one (like type/content/clear text) (e.g when an encrypted message from
-                    // FCM should be update with clear text after a sync)
-                    // In this case the message has already been notified, and might have done some noise
-                    // So we want the notification to be updated even if it has already been displayed
-                    // Use setOnlyAlertOnce to ensure update notification does not interfere with sound
-                    // from first notify invocation as outlined in:
-                    // https://developer.android.com/training/notify-user/build-notification#Updating
-                    notifiableEvent.hasBeenDisplayed = false
-                    eventList.remove(existing)
-                    eventList.add(notifiableEvent)
-                } else {
-                    // keep the existing one, do not replace
-                }
-            } else {
-                // Check if this is an edit
-                if (notifiableEvent.editedEventId != null) {
-                    // This is an edition
-                    val eventBeforeEdition = eventList.firstOrNull {
-                        // Edition of an event
-                        it.eventId == notifiableEvent.editedEventId ||
-                                // or edition of an edition
-                                it.editedEventId == notifiableEvent.editedEventId
-                    }
 
-                    if (eventBeforeEdition != null) {
-                        // Replace the existing notification with the new content
-                        eventList.remove(eventBeforeEdition)
-
-                        eventList.add(notifiableEvent)
-                    } else {
-                        // Ignore an edit of a not displayed event in the notification drawer
-                    }
-                } else {
-                    // Not an edit
-                    if (seenEventIds.contains(notifiableEvent.eventId)) {
-                        // we've already seen the event, lets skip
-                        Timber.d("onNotifiableEventReceived(): skipping event, already seen")
-                    } else {
-                        seenEventIds.put(notifiableEvent.eventId)
-                        eventList.add(notifiableEvent)
-                    }
-                }
-            }
-        }
-    }
-
-    fun onEventRedacted(eventId: String) {
-        synchronized(eventList) {
-            eventList.find { it.eventId == eventId }?.apply {
-                isRedacted = true
-                hasBeenDisplayed = false
-            }
-        }
+        add(notifiableEvent, seenEventIds)
     }
 
     /**
      * Clear all known events and refresh the notification drawer
      */
     fun clearAllEvents() {
-        synchronized(eventList) {
-            eventList.clear()
-        }
-        refreshNotificationDrawer()
-    }
-
-    /** Clear all known message events for this room */
-    fun clearMessageEventOfRoom(roomId: String?) {
-        Timber.v("clearMessageEventOfRoom $roomId")
-        if (roomId != null) {
-            var shouldUpdate = false
-            synchronized(eventList) {
-                shouldUpdate = eventList.removeAll { e ->
-                    e is NotifiableMessageEvent && e.roomId == roomId
-                }
-            }
-            if (shouldUpdate) {
-                notificationUtils.cancelNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID)
-                refreshNotificationDrawer()
-            }
-        }
+        updateEvents { it.clear() }
     }
 
     /**
@@ -201,28 +121,36 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
      * Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
      */
     fun setCurrentRoom(roomId: String?) {
-        var hasChanged: Boolean
-        synchronized(eventList) {
-            hasChanged = roomId != currentRoomId
+        updateEvents {
+            val hasChanged = roomId != currentRoomId
             currentRoomId = roomId
-        }
-        if (hasChanged) {
-            clearMessageEventOfRoom(roomId)
+            if (hasChanged && roomId != null) {
+                it.clearMessagesForRoom(roomId)
+            }
         }
     }
 
-    fun clearMemberShipNotificationForRoom(roomId: String) {
-        synchronized(eventList) {
-            eventList.removeAll { e ->
-                e is InviteNotifiableEvent && e.roomId == roomId
+    fun notificationStyleChanged() {
+        updateEvents {
+            val newSettings = vectorPreferences.useCompleteNotificationFormat()
+            if (newSettings != useCompleteNotificationFormat) {
+                // Settings has changed, remove all current notifications
+                notificationDisplayer.cancelAllNotifications()
+                useCompleteNotificationFormat = newSettings
             }
         }
-        notificationUtils.cancelNotificationMessage(roomId, ROOM_INVITATION_NOTIFICATION_ID)
+    }
+
+    fun updateEvents(action: NotificationDrawerManager.(NotificationEventQueue) -> Unit) {
+        synchronized(queuedEvents) {
+            action(this, queuedEvents)
+        }
+        refreshNotificationDrawer()
     }
 
     private var firstThrottler = FirstThrottler(200)
 
-    fun refreshNotificationDrawer() {
+    private fun refreshNotificationDrawer() {
         // Implement last throttler
         val canHandle = firstThrottler.canHandle()
         Timber.v("refreshNotificationDrawer(), delay: ${canHandle.waitMillis()} ms")
@@ -243,373 +171,28 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
     @WorkerThread
     private fun refreshNotificationDrawerBg() {
         Timber.v("refreshNotificationDrawerBg()")
-
-        val session = currentSession ?: return
-
-        val user = session.getUser(session.myUserId)
-        // myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
-        val myUserDisplayName = user?.toMatrixItem()?.getBestName() ?: session.myUserId
-        val myUserAvatarUrl = session.contentUrlResolver().resolveThumbnail(user?.avatarUrl, avatarSize, avatarSize, ContentUrlResolver.ThumbnailMethod.SCALE)
-        synchronized(eventList) {
-            Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER ")
-            // TMP code
-            var hasNewEvent = false
-            var summaryIsNoisy = false
-            val summaryInboxStyle = NotificationCompat.InboxStyle()
-
-            // group events by room to create a single MessagingStyle notif
-            val roomIdToEventMap: MutableMap<String, MutableList<NotifiableMessageEvent>> = LinkedHashMap()
-            val simpleEvents: MutableList<SimpleNotifiableEvent> = ArrayList()
-            val invitationEvents: MutableList<InviteNotifiableEvent> = ArrayList()
-
-            val eventIterator = eventList.listIterator()
-            while (eventIterator.hasNext()) {
-                when (val event = eventIterator.next()) {
-                    is NotifiableMessageEvent -> {
-                        val roomId = event.roomId
-                        val roomEvents = roomIdToEventMap.getOrPut(roomId) { ArrayList() }
-
-                        if (shouldIgnoreMessageEventInRoom(roomId) || outdatedDetector?.isMessageOutdated(event) == true) {
-                            // forget this event
-                            eventIterator.remove()
-                        } else {
-                            roomEvents.add(event)
-                        }
-                    }
-                    is InviteNotifiableEvent  -> {
-                        if (autoAcceptInvites.hideInvites) {
-                            // Forget this event
-                            eventIterator.remove()
-                        } else {
-                            invitationEvents.add(event)
-                        }
-                    }
-                    is SimpleNotifiableEvent  -> simpleEvents.add(event)
-                    else                      -> Timber.w("Type not handled")
-                }
+        val eventsToRender = synchronized(queuedEvents) {
+            notifiableEventProcessor.process(queuedEvents.rawEvents(), currentRoomId, renderedEvents).also {
+                queuedEvents.clearAndAdd(it.onlyKeptEvents())
             }
-
-            Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER ${roomIdToEventMap.size} room groups")
-
-            var globalLastMessageTimestamp = 0L
-
-            val newSettings = vectorPreferences.useCompleteNotificationFormat()
-            if (newSettings != useCompleteNotificationFormat) {
-                // Settings has changed, remove all current notifications
-                notificationUtils.cancelAllNotifications()
-                useCompleteNotificationFormat = newSettings
-            }
-
-            var simpleNotificationRoomCounter = 0
-            var simpleNotificationMessageCounter = 0
-
-            // events have been grouped by roomId
-            for ((roomId, events) in roomIdToEventMap) {
-                // Build the notification for the room
-                if (events.isEmpty() || events.all { it.isRedacted }) {
-                    // Just clear this notification
-                    Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER $roomId has no more events")
-                    notificationUtils.cancelNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID)
-                    continue
-                }
-
-                simpleNotificationRoomCounter++
-                val roomName = events[0].roomName ?: events[0].senderName ?: ""
-
-                val roomEventGroupInfo = RoomEventGroupInfo(
-                        roomId = roomId,
-                        isDirect = events[0].roomIsDirect,
-                        roomDisplayName = roomName)
-
-                val style = NotificationCompat.MessagingStyle(Person.Builder()
-                        .setName(myUserDisplayName)
-                        .setIcon(iconLoader.getUserIcon(myUserAvatarUrl))
-                        .setKey(events[0].matrixID)
-                        .build())
-
-                style.isGroupConversation = !roomEventGroupInfo.isDirect
-
-                if (!roomEventGroupInfo.isDirect) {
-                    style.conversationTitle = roomEventGroupInfo.roomDisplayName
-                }
-
-                val largeBitmap = getRoomBitmap(events)
-
-                for (event in events) {
-                    // if all events in this room have already been displayed there is no need to update it
-                    if (!event.hasBeenDisplayed && !event.isRedacted) {
-                        roomEventGroupInfo.shouldBing = roomEventGroupInfo.shouldBing || event.noisy
-                        roomEventGroupInfo.customSound = event.soundName
-                    }
-                    roomEventGroupInfo.hasNewEvent = roomEventGroupInfo.hasNewEvent || !event.hasBeenDisplayed
-
-                    val senderPerson = if (event.outGoingMessage) {
-                        null
-                    } else {
-                        Person.Builder()
-                                .setName(event.senderName)
-                                .setIcon(iconLoader.getUserIcon(event.senderAvatarPath))
-                                .setKey(event.senderId)
-                                .build()
-                    }
-
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-                        val openRoomIntent = RoomDetailActivity.shortcutIntent(context, roomId)
-
-                        val shortcut = ShortcutInfoCompat.Builder(context, roomId)
-                                .setLongLived(true)
-                                .setIntent(openRoomIntent)
-                                .setShortLabel(roomName)
-                                .setIcon(largeBitmap?.let { IconCompat.createWithAdaptiveBitmap(it) } ?: iconLoader.getUserIcon(event.senderAvatarPath))
-                                .build()
-
-                        ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
-                    }
-
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-                        val openRoomIntent = RoomDetailActivity.shortcutIntent(context, roomId)
-
-                        val shortcut = ShortcutInfoCompat.Builder(context, roomId)
-                                .setLongLived(true)
-                                .setIntent(openRoomIntent)
-                                .setShortLabel(roomName)
-                                .setIcon(largeBitmap?.let { IconCompat.createWithAdaptiveBitmap(it) } ?: iconLoader.getUserIcon(event.senderAvatarPath))
-                                .build()
-
-                        ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
-                    }
-
-                    if (event.outGoingMessage && event.outGoingMessageFailed) {
-                        style.addMessage(stringProvider.getString(R.string.notification_inline_reply_failed), event.timestamp, senderPerson)
-                        roomEventGroupInfo.hasSmartReplyError = true
-                    } else {
-                        if (!event.isRedacted) {
-                            simpleNotificationMessageCounter++
-                            style.addMessage(event.body, event.timestamp, senderPerson)
-                        }
-                    }
-                    event.hasBeenDisplayed = true // we can consider it as displayed
-
-                    // It is possible that this event was previously shown as an 'anonymous' simple notif.
-                    // And now it will be merged in a single MessageStyle notif, so we can clean to be sure
-                    notificationUtils.cancelNotificationMessage(event.eventId, ROOM_EVENT_NOTIFICATION_ID)
-                }
-
-                try {
-                    if (events.size == 1) {
-                        val event = events[0]
-                        if (roomEventGroupInfo.isDirect) {
-                            val line = span {
-                                span {
-                                    textStyle = "bold"
-                                    +String.format("%s: ", event.senderName)
-                                }
-                                +(event.description ?: "")
-                            }
-                            summaryInboxStyle.addLine(line)
-                        } else {
-                            val line = span {
-                                span {
-                                    textStyle = "bold"
-                                    +String.format("%s: %s ", roomName, event.senderName)
-                                }
-                                +(event.description ?: "")
-                            }
-                            summaryInboxStyle.addLine(line)
-                        }
-                    } else {
-                        val summaryLine = stringProvider.getQuantityString(
-                                R.plurals.notification_compat_summary_line_for_room, events.size, roomName, events.size)
-                        summaryInboxStyle.addLine(summaryLine)
-                    }
-                } catch (e: Throwable) {
-                    // String not found or bad format
-                    Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER failed to resolve string")
-                    summaryInboxStyle.addLine(roomName)
-                }
-
-                if (firstTime || roomEventGroupInfo.hasNewEvent) {
-                    // Should update displayed notification
-                    Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER $roomId need refresh")
-                    val lastMessageTimestamp = events.last().timestamp
-
-                    if (globalLastMessageTimestamp < lastMessageTimestamp) {
-                        globalLastMessageTimestamp = lastMessageTimestamp
-                    }
-
-                    val tickerText = if (roomEventGroupInfo.isDirect) {
-                        stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderName, events.last().description)
-                    } else {
-                        stringProvider.getString(R.string.notification_ticker_text_group, roomName, events.last().senderName, events.last().description)
-                    }
-
-                    if (useCompleteNotificationFormat) {
-                        val notification = notificationUtils.buildMessagesListNotification(
-                                style,
-                                roomEventGroupInfo,
-                                largeBitmap,
-                                lastMessageTimestamp,
-                                myUserDisplayName,
-                                tickerText)
-
-                        // is there an id for this room?
-                        notificationUtils.showNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID, notification)
-                    }
-
-                    hasNewEvent = true
-                    summaryIsNoisy = summaryIsNoisy || roomEventGroupInfo.shouldBing
-                } else {
-                    Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER $roomId is up to date")
-                }
-            }
-
-            // Handle invitation events
-            for (event in invitationEvents) {
-                // We build a invitation notification
-                if (firstTime || !event.hasBeenDisplayed) {
-                    if (useCompleteNotificationFormat) {
-                        val notification = notificationUtils.buildRoomInvitationNotification(event, session.myUserId)
-                        notificationUtils.showNotificationMessage(event.roomId, ROOM_INVITATION_NOTIFICATION_ID, notification)
-                    }
-                    event.hasBeenDisplayed = true // we can consider it as displayed
-                    hasNewEvent = true
-                    summaryIsNoisy = summaryIsNoisy || event.noisy
-                    summaryInboxStyle.addLine(event.description)
-                }
-            }
-
-            // Handle simple events
-            for (event in simpleEvents) {
-                // We build a simple notification
-                if (firstTime || !event.hasBeenDisplayed) {
-                    if (useCompleteNotificationFormat) {
-                        val notification = notificationUtils.buildSimpleEventNotification(event, session.myUserId)
-                        notificationUtils.showNotificationMessage(event.eventId, ROOM_EVENT_NOTIFICATION_ID, notification)
-                    }
-                    event.hasBeenDisplayed = true // we can consider it as displayed
-                    hasNewEvent = true
-                    summaryIsNoisy = summaryIsNoisy || event.noisy
-                    summaryInboxStyle.addLine(event.description)
-                }
-            }
-
-            // ======== Build summary notification =========
-            // On Android 7.0 (API level 24) and higher, the system automatically builds a summary for
-            // your group using snippets of text from each notification. The user can expand this
-            // notification to see each separate notification.
-            // To support older versions, which cannot show a nested group of notifications,
-            // you must create an extra notification that acts as the summary.
-            // This appears as the only notification and the system hides all the others.
-            // So this summary should include a snippet from all the other notifications,
-            // which the user can tap to open your app.
-            // The behavior of the group summary may vary on some device types such as wearables.
-            // To ensure the best experience on all devices and versions, always include a group summary when you create a group
-            // https://developer.android.com/training/notify-user/group
-
-            if (eventList.isEmpty() || eventList.all { it.isRedacted }) {
-                notificationUtils.cancelNotificationMessage(null, SUMMARY_NOTIFICATION_ID)
-            } else if (hasNewEvent) {
-                // FIXME roomIdToEventMap.size is not correct, this is the number of rooms
-                val nbEvents = roomIdToEventMap.size + simpleEvents.size
-                val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
-                summaryInboxStyle.setBigContentTitle(sumTitle)
-                        // TODO get latest event?
-                        .setSummaryText(stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents))
-
-                if (useCompleteNotificationFormat) {
-                    val notification = notificationUtils.buildSummaryListNotification(
-                            summaryInboxStyle,
-                            sumTitle,
-                            noisy = hasNewEvent && summaryIsNoisy,
-                            lastMessageTimestamp = globalLastMessageTimestamp)
-
-                    notificationUtils.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, notification)
-                } else {
-                    // Add the simple events as message (?)
-                    simpleNotificationMessageCounter += simpleEvents.size
-                    val numberOfInvitations = invitationEvents.size
-
-                    val privacyTitle = if (numberOfInvitations > 0) {
-                        val invitationsStr = stringProvider.getQuantityString(R.plurals.notification_invitations, numberOfInvitations, numberOfInvitations)
-                        if (simpleNotificationMessageCounter > 0) {
-                            // Invitation and message
-                            val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification,
-                                    simpleNotificationMessageCounter, simpleNotificationMessageCounter)
-                            if (simpleNotificationRoomCounter > 1) {
-                                // In several rooms
-                                val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms,
-                                        simpleNotificationRoomCounter, simpleNotificationRoomCounter)
-                                stringProvider.getString(
-                                        R.string.notification_unread_notified_messages_in_room_and_invitation,
-                                        messageStr,
-                                        roomStr,
-                                        invitationsStr
-                                )
-                            } else {
-                                // In one room
-                                stringProvider.getString(
-                                        R.string.notification_unread_notified_messages_and_invitation,
-                                        messageStr,
-                                        invitationsStr
-                                )
-                            }
-                        } else {
-                            // Only invitation
-                            invitationsStr
-                        }
-                    } else {
-                        // No invitation, only messages
-                        val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification,
-                                simpleNotificationMessageCounter, simpleNotificationMessageCounter)
-                        if (simpleNotificationRoomCounter > 1) {
-                            // In several rooms
-                            val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms,
-                                    simpleNotificationRoomCounter, simpleNotificationRoomCounter)
-                            stringProvider.getString(R.string.notification_unread_notified_messages_in_room, messageStr, roomStr)
-                        } else {
-                            // In one room
-                            messageStr
-                        }
-                    }
-                    val notification = notificationUtils.buildSummaryListNotification(
-                            style = null,
-                            compatSummary = privacyTitle,
-                            noisy = hasNewEvent && summaryIsNoisy,
-                            lastMessageTimestamp = globalLastMessageTimestamp)
-
-                    notificationUtils.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, notification)
-                }
-
-                if (hasNewEvent && summaryIsNoisy) {
-                    try {
-                        // turn the screen on for 3 seconds
-                        /*
-                        TODO
-                        if (Matrix.getInstance(VectorApp.getInstance())!!.pushManager.isScreenTurnedOn) {
-                            val pm = VectorApp.getInstance().getSystemService<PowerManager>()!!
-                            val wl = pm.newWakeLock(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or PowerManager.ACQUIRE_CAUSES_WAKEUP,
-                                    NotificationDrawerManager::class.java.name)
-                            wl.acquire(3000)
-                            wl.release()
-                        }
-                         */
-                    } catch (e: Throwable) {
-                        Timber.e(e, "## Failed to turn screen on")
-                    }
-                }
-            }
-            // notice that we can get bit out of sync with actual display but not a big issue
-            firstTime = false
         }
-    }
 
-    private fun getRoomBitmap(events: List<NotifiableMessageEvent>): Bitmap? {
-        if (events.isEmpty()) return null
-
-        // Use the last event (most recent?)
-        val roomAvatarPath = events.last().roomAvatarPath ?: events.last().senderAvatarPath
-
-        return bitmapLoader.getRoomBitmap(roomAvatarPath)
+        if (renderedEvents == eventsToRender) {
+            Timber.d("Skipping notification update due to event list not changing")
+        } else {
+            renderedEvents = eventsToRender
+            val session = currentSession ?: return
+            val user = session.getUser(session.myUserId)
+            // myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
+            val myUserDisplayName = user?.toMatrixItem()?.getBestName() ?: session.myUserId
+            val myUserAvatarUrl = session.contentUrlResolver().resolveThumbnail(
+                    contentUrl = user?.avatarUrl,
+                    width = avatarSize,
+                    height = avatarSize,
+                    method = ContentUrlResolver.ThumbnailMethod.SCALE
+            )
+            notificationRenderer.render(session.myUserId, myUserDisplayName, myUserAvatarUrl, useCompleteNotificationFormat, eventsToRender)
+        }
     }
 
     fun shouldIgnoreMessageEventInRoom(roomId: String?): Boolean {
@@ -617,8 +200,8 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
     }
 
     fun persistInfo() {
-        synchronized(eventList) {
-            if (eventList.isEmpty()) {
+        synchronized(queuedEvents) {
+            if (queuedEvents.isEmpty()) {
                 deleteCachedRoomNotifications()
                 return
             }
@@ -626,7 +209,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
                 val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
                 if (!file.exists()) file.createNewFile()
                 FileOutputStream(file).use {
-                    currentSession?.securelyStoreObject(eventList, KEY_ALIAS_SECRET_STORAGE, it)
+                    currentSession?.securelyStoreObject(queuedEvents.rawEvents(), KEY_ALIAS_SECRET_STORAGE, it)
                 }
             } catch (e: Throwable) {
                 Timber.e(e, "## Failed to save cached notification info")
@@ -634,21 +217,21 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
         }
     }
 
-    private fun loadEventInfo(): MutableList<NotifiableEvent> {
+    private fun loadEventInfo(): NotificationEventQueue {
         try {
             val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
             if (file.exists()) {
                 file.inputStream().use {
                     val events: ArrayList<NotifiableEvent>? = currentSession?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
                     if (events != null) {
-                        return events.toMutableList()
+                        return NotificationEventQueue(events.toMutableList())
                     }
                 }
             }
         } catch (e: Throwable) {
             Timber.e(e, "## Failed to load cached notification info")
         }
-        return ArrayList()
+        return NotificationEventQueue()
     }
 
     private fun deleteCachedRoomNotifications() {
@@ -658,15 +241,11 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
         }
     }
 
-    fun displayDiagnosticNotification() {
-        notificationUtils.displayDiagnosticNotification()
-    }
-
     companion object {
-        private const val SUMMARY_NOTIFICATION_ID = 0
-        private const val ROOM_MESSAGES_NOTIFICATION_ID = 1
-        private const val ROOM_EVENT_NOTIFICATION_ID = 2
-        private const val ROOM_INVITATION_NOTIFICATION_ID = 3
+        const val SUMMARY_NOTIFICATION_ID = 0
+        const val ROOM_MESSAGES_NOTIFICATION_ID = 1
+        const val ROOM_EVENT_NOTIFICATION_ID = 2
+        const val ROOM_INVITATION_NOTIFICATION_ID = 3
 
         // TODO Mutliaccount
         private const val ROOMS_NOTIFICATIONS_FILE_NAME = "im.vector.notifications.cache"
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationEventQueue.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationEventQueue.kt
new file mode 100644
index 0000000000..83beb4fa02
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationEventQueue.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import timber.log.Timber
+
+class NotificationEventQueue(
+        private val queue: MutableList<NotifiableEvent> = mutableListOf()
+) {
+
+    fun markRedacted(eventIds: List<String>) {
+        eventIds.forEach { redactedId ->
+            queue.replace(redactedId) {
+                when (it) {
+                    is InviteNotifiableEvent  -> it.copy(isRedacted = true)
+                    is NotifiableMessageEvent -> it.copy(isRedacted = true)
+                    is SimpleNotifiableEvent  -> it.copy(isRedacted = true)
+                }
+            }
+        }
+    }
+
+    fun syncRoomEvents(roomsLeft: Collection<String>, roomsJoined: Collection<String>) {
+        if (roomsLeft.isNotEmpty() || roomsJoined.isNotEmpty()) {
+            queue.removeAll {
+                when (it) {
+                    is NotifiableMessageEvent -> roomsLeft.contains(it.roomId)
+                    is InviteNotifiableEvent  -> roomsLeft.contains(it.roomId) || roomsJoined.contains(it.roomId)
+                    else                      -> false
+                }
+            }
+        }
+    }
+
+    fun isEmpty() = queue.isEmpty()
+
+    fun clearAndAdd(events: List<NotifiableEvent>) {
+        queue.clear()
+        queue.addAll(events)
+    }
+
+    fun clear() {
+        queue.clear()
+    }
+
+    fun add(notifiableEvent: NotifiableEvent, seenEventIds: CircularCache<String>) {
+        val existing = findExistingById(notifiableEvent)
+        val edited = findEdited(notifiableEvent)
+        when {
+            existing != null                               -> {
+                if (existing.canBeReplaced) {
+                    // Use the event coming from the event stream as it may contains more info than
+                    // the fcm one (like type/content/clear text) (e.g when an encrypted message from
+                    // FCM should be update with clear text after a sync)
+                    // In this case the message has already been notified, and might have done some noise
+                    // So we want the notification to be updated even if it has already been displayed
+                    // Use setOnlyAlertOnce to ensure update notification does not interfere with sound
+                    // from first notify invocation as outlined in:
+                    // https://developer.android.com/training/notify-user/build-notification#Updating
+                    replace(replace = existing, with = notifiableEvent)
+                } else {
+                    // keep the existing one, do not replace
+                }
+            }
+            edited != null                                 -> {
+                // Replace the existing notification with the new content
+                replace(replace = edited, with = notifiableEvent)
+            }
+            seenEventIds.contains(notifiableEvent.eventId) -> {
+                // we've already seen the event, lets skip
+                Timber.d("onNotifiableEventReceived(): skipping event, already seen")
+            }
+            else                                           -> {
+                seenEventIds.put(notifiableEvent.eventId)
+                queue.add(notifiableEvent)
+            }
+        }
+    }
+
+    private fun findExistingById(notifiableEvent: NotifiableEvent): NotifiableEvent? {
+        return queue.firstOrNull { it.eventId == notifiableEvent.eventId }
+    }
+
+    private fun findEdited(notifiableEvent: NotifiableEvent): NotifiableEvent? {
+        return notifiableEvent.editedEventId?.let { editedId ->
+            queue.firstOrNull {
+                it.eventId == editedId || it.editedEventId == editedId
+            }
+        }
+    }
+
+    private fun replace(replace: NotifiableEvent, with: NotifiableEvent) {
+        queue.remove(replace)
+        queue.add(with)
+    }
+
+    fun clearMemberShipNotificationForRoom(roomId: String) {
+        Timber.v("clearMemberShipOfRoom $roomId")
+        queue.removeAll { it is InviteNotifiableEvent && it.roomId == roomId }
+    }
+
+    fun clearMessagesForRoom(roomId: String) {
+        Timber.v("clearMessageEventOfRoom $roomId")
+        queue.removeAll { it is NotifiableMessageEvent && it.roomId == roomId }
+    }
+
+    fun rawEvents(): List<NotifiableEvent> = queue
+}
+
+private fun MutableList<NotifiableEvent>.replace(eventId: String, block: (NotifiableEvent) -> NotifiableEvent) {
+    val indexToReplace = indexOfFirst { it.eventId == eventId }
+    if (indexToReplace == -1) {
+        return
+    }
+    set(indexToReplace, block(get(indexToReplace)))
+}
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationFactory.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationFactory.kt
new file mode 100644
index 0000000000..b95bbe1bf5
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationFactory.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import android.app.Notification
+import javax.inject.Inject
+
+private typealias ProcessedMessageEvents = List<ProcessedEvent<NotifiableMessageEvent>>
+
+class NotificationFactory @Inject constructor(
+        private val notificationUtils: NotificationUtils,
+        private val roomGroupMessageCreator: RoomGroupMessageCreator,
+        private val summaryGroupMessageCreator: SummaryGroupMessageCreator
+) {
+
+    fun Map<String, ProcessedMessageEvents>.toNotifications(myUserDisplayName: String, myUserAvatarUrl: String?): List<RoomNotification> {
+        return map { (roomId, events) ->
+            when {
+                events.hasNoEventsToDisplay() -> RoomNotification.Removed(roomId)
+                else                          -> {
+                    val messageEvents = events.onlyKeptEvents().filterNot { it.isRedacted }
+                    roomGroupMessageCreator.createRoomMessage(messageEvents, roomId, myUserDisplayName, myUserAvatarUrl)
+                }
+            }
+        }
+    }
+
+    private fun ProcessedMessageEvents.hasNoEventsToDisplay() = isEmpty() || all {
+        it.type == ProcessedEvent.Type.REMOVE || it.event.canNotBeDisplayed()
+    }
+
+    private fun NotifiableMessageEvent.canNotBeDisplayed() = isRedacted
+
+    @JvmName("toNotificationsInviteNotifiableEvent")
+    fun List<ProcessedEvent<InviteNotifiableEvent>>.toNotifications(myUserId: String): List<OneShotNotification> {
+        return map { (processed, event) ->
+            when (processed) {
+                ProcessedEvent.Type.REMOVE -> OneShotNotification.Removed(key = event.roomId)
+                ProcessedEvent.Type.KEEP   -> OneShotNotification.Append(
+                        notificationUtils.buildRoomInvitationNotification(event, myUserId),
+                        OneShotNotification.Append.Meta(
+                                key = event.roomId,
+                                summaryLine = event.description,
+                                isNoisy = event.noisy,
+                                timestamp = event.timestamp
+                        )
+                )
+            }
+        }
+    }
+
+    @JvmName("toNotificationsSimpleNotifiableEvent")
+    fun List<ProcessedEvent<SimpleNotifiableEvent>>.toNotifications(myUserId: String): List<OneShotNotification> {
+        return map { (processed, event) ->
+            when (processed) {
+                ProcessedEvent.Type.REMOVE -> OneShotNotification.Removed(key = event.eventId)
+                ProcessedEvent.Type.KEEP   -> OneShotNotification.Append(
+                        notificationUtils.buildSimpleEventNotification(event, myUserId),
+                        OneShotNotification.Append.Meta(
+                                key = event.eventId,
+                                summaryLine = event.description,
+                                isNoisy = event.noisy,
+                                timestamp = event.timestamp
+                        )
+                )
+            }
+        }
+    }
+
+    fun createSummaryNotification(roomNotifications: List<RoomNotification>,
+                                  invitationNotifications: List<OneShotNotification>,
+                                  simpleNotifications: List<OneShotNotification>,
+                                  useCompleteNotificationFormat: Boolean): SummaryNotification {
+        val roomMeta = roomNotifications.filterIsInstance<RoomNotification.Message>().map { it.meta }
+        val invitationMeta = invitationNotifications.filterIsInstance<OneShotNotification.Append>().map { it.meta }
+        val simpleMeta = simpleNotifications.filterIsInstance<OneShotNotification.Append>().map { it.meta }
+        return when {
+            roomMeta.isEmpty() && invitationMeta.isEmpty() && simpleMeta.isEmpty() -> SummaryNotification.Removed
+            else                                                                   -> SummaryNotification.Update(
+                    summaryGroupMessageCreator.createSummaryNotification(
+                            roomNotifications = roomMeta,
+                            invitationNotifications = invitationMeta,
+                            simpleNotifications = simpleMeta,
+                            useCompleteNotificationFormat = useCompleteNotificationFormat
+                    ))
+        }
+    }
+}
+
+sealed interface RoomNotification {
+    data class Removed(val roomId: String) : RoomNotification
+    data class Message(val notification: Notification, val meta: Meta) : RoomNotification {
+        data class Meta(
+                val summaryLine: CharSequence,
+                val messageCount: Int,
+                val latestTimestamp: Long,
+                val roomId: String,
+                val shouldBing: Boolean
+        )
+    }
+}
+
+sealed interface OneShotNotification {
+    data class Removed(val key: String) : OneShotNotification
+    data class Append(val notification: Notification, val meta: Meta) : OneShotNotification {
+        data class Meta(
+                val key: String,
+                val summaryLine: CharSequence,
+                val isNoisy: Boolean,
+                val timestamp: Long,
+        )
+    }
+}
+
+sealed interface SummaryNotification {
+    object Removed : SummaryNotification
+    data class Update(val notification: Notification) : SummaryNotification
+}
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationRenderer.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationRenderer.kt
new file mode 100644
index 0000000000..4078bb0b5c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationRenderer.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package im.vector.app.features.notifications
+
+import android.content.Context
+import androidx.annotation.WorkerThread
+import im.vector.app.features.notifications.NotificationDrawerManager.Companion.ROOM_EVENT_NOTIFICATION_ID
+import im.vector.app.features.notifications.NotificationDrawerManager.Companion.ROOM_INVITATION_NOTIFICATION_ID
+import im.vector.app.features.notifications.NotificationDrawerManager.Companion.ROOM_MESSAGES_NOTIFICATION_ID
+import im.vector.app.features.notifications.NotificationDrawerManager.Companion.SUMMARY_NOTIFICATION_ID
+import timber.log.Timber
+import javax.inject.Inject
+
+class NotificationRenderer @Inject constructor(private val notificationDisplayer: NotificationDisplayer,
+                                               private val notificationFactory: NotificationFactory,
+                                               private val appContext: Context) {
+
+    @WorkerThread
+    fun render(myUserId: String,
+               myUserDisplayName: String,
+               myUserAvatarUrl: String?,
+               useCompleteNotificationFormat: Boolean,
+               eventsToProcess: List<ProcessedEvent<NotifiableEvent>>) {
+        val (roomEvents, simpleEvents, invitationEvents) = eventsToProcess.groupByType()
+        with(notificationFactory) {
+            val roomNotifications = roomEvents.toNotifications(myUserDisplayName, myUserAvatarUrl)
+            val invitationNotifications = invitationEvents.toNotifications(myUserId)
+            val simpleNotifications = simpleEvents.toNotifications(myUserId)
+            val summaryNotification = createSummaryNotification(
+                    roomNotifications = roomNotifications,
+                    invitationNotifications = invitationNotifications,
+                    simpleNotifications = simpleNotifications,
+                    useCompleteNotificationFormat = useCompleteNotificationFormat
+            )
+
+            // Remove summary first to avoid briefly displaying it after dismissing the last notification
+            when (summaryNotification) {
+                SummaryNotification.Removed -> {
+                    Timber.d("Removing summary notification")
+                    notificationDisplayer.cancelNotificationMessage(null, SUMMARY_NOTIFICATION_ID)
+                }
+            }
+
+            roomNotifications.forEach { wrapper ->
+                when (wrapper) {
+                    is RoomNotification.Removed -> {
+                        Timber.d("Removing room messages notification ${wrapper.roomId}")
+                        notificationDisplayer.cancelNotificationMessage(wrapper.roomId, ROOM_MESSAGES_NOTIFICATION_ID)
+                    }
+                    is RoomNotification.Message -> if (useCompleteNotificationFormat) {
+                        Timber.d("Updating room messages notification ${wrapper.meta.roomId}")
+                        notificationDisplayer.showNotificationMessage(wrapper.meta.roomId, ROOM_MESSAGES_NOTIFICATION_ID, wrapper.notification)
+                    }
+                }
+            }
+
+            invitationNotifications.forEach { wrapper ->
+                when (wrapper) {
+                    is OneShotNotification.Removed -> {
+                        Timber.d("Removing invitation notification ${wrapper.key}")
+                        notificationDisplayer.cancelNotificationMessage(wrapper.key, ROOM_INVITATION_NOTIFICATION_ID)
+                    }
+                    is OneShotNotification.Append  -> if (useCompleteNotificationFormat) {
+                        Timber.d("Updating invitation notification ${wrapper.meta.key}")
+                        notificationDisplayer.showNotificationMessage(wrapper.meta.key, ROOM_INVITATION_NOTIFICATION_ID, wrapper.notification)
+                    }
+                }
+            }
+
+            simpleNotifications.forEach { wrapper ->
+                when (wrapper) {
+                    is OneShotNotification.Removed -> {
+                        Timber.d("Removing simple notification ${wrapper.key}")
+                        notificationDisplayer.cancelNotificationMessage(wrapper.key, ROOM_EVENT_NOTIFICATION_ID)
+                    }
+                    is OneShotNotification.Append  -> if (useCompleteNotificationFormat) {
+                        Timber.d("Updating simple notification ${wrapper.meta.key}")
+                        notificationDisplayer.showNotificationMessage(wrapper.meta.key, ROOM_EVENT_NOTIFICATION_ID, wrapper.notification)
+                    }
+                }
+            }
+
+            // Update summary last to avoid briefly displaying it before other notifications
+            when (summaryNotification) {
+                is SummaryNotification.Update -> {
+                    Timber.d("Updating summary notification")
+                    notificationDisplayer.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, summaryNotification.notification)
+                }
+            }
+        }
+    }
+}
+
+private fun List<ProcessedEvent<NotifiableEvent>>.groupByType(): GroupedNotificationEvents {
+    val roomIdToEventMap: MutableMap<String, MutableList<ProcessedEvent<NotifiableMessageEvent>>> = LinkedHashMap()
+    val simpleEvents: MutableList<ProcessedEvent<SimpleNotifiableEvent>> = ArrayList()
+    val invitationEvents: MutableList<ProcessedEvent<InviteNotifiableEvent>> = ArrayList()
+    forEach {
+        when (val event = it.event) {
+            is InviteNotifiableEvent  -> invitationEvents.add(it.castedToEventType())
+            is NotifiableMessageEvent -> {
+                val roomEvents = roomIdToEventMap.getOrPut(event.roomId) { ArrayList() }
+                roomEvents.add(it.castedToEventType())
+            }
+            is SimpleNotifiableEvent  -> simpleEvents.add(it.castedToEventType())
+        }
+    }
+    return GroupedNotificationEvents(roomIdToEventMap, simpleEvents, invitationEvents)
+}
+
+@Suppress("UNCHECKED_CAST")
+private fun <T : NotifiableEvent> ProcessedEvent<NotifiableEvent>.castedToEventType(): ProcessedEvent<T> = this as ProcessedEvent<T>
+
+data class GroupedNotificationEvents(
+        val roomEvents: Map<String, List<ProcessedEvent<NotifiableMessageEvent>>>,
+        val simpleEvents: List<ProcessedEvent<SimpleNotifiableEvent>>,
+        val invitationEvents: List<ProcessedEvent<InviteNotifiableEvent>>
+)
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt
index d4b922d8bc..3edb5afd3d 100755
--- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt
@@ -47,6 +47,7 @@ import androidx.fragment.app.Fragment
 import im.vector.app.BuildConfig
 import im.vector.app.R
 import im.vector.app.core.extensions.createIgnoredUri
+import im.vector.app.core.platform.PendingIntentCompat
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.services.CallService
 import im.vector.app.core.utils.startNotificationChannelSettingsIntent
@@ -226,7 +227,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
         // build the pending intent go to the home screen if this is clicked.
         val i = HomeActivity.newIntent(context)
         i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
-        val pi = PendingIntent.getActivity(context, 0, i, 0)
+        val pi = PendingIntent.getActivity(context, 0, i, PendingIntentCompat.FLAG_IMMUTABLE)
 
         val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
 
@@ -319,16 +320,23 @@ class NotificationUtils @Inject constructor(private val context: Context,
             flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
             data = createIgnoredUri(call.callId)
         }
-        val contentPendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), contentIntent, 0)
+        val contentPendingIntent = PendingIntent.getActivity(
+                context,
+                System.currentTimeMillis().toInt(),
+                contentIntent,
+                PendingIntentCompat.FLAG_IMMUTABLE
+        )
 
         val answerCallPendingIntent = TaskStackBuilder.create(context)
                 .addNextIntentWithParentStack(HomeActivity.newIntent(context))
-                .addNextIntent(VectorCallActivity.newIntent(
-                        context = context,
-                        call = call,
-                        mode = VectorCallActivity.INCOMING_ACCEPT)
+                .addNextIntent(
+                        VectorCallActivity.newIntent(
+                                context = context,
+                                call = call,
+                                mode = VectorCallActivity.INCOMING_ACCEPT
+                        )
                 )
-                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
+                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
 
         val rejectCallPendingIntent = buildRejectCallPendingIntent(call.callId)
 
@@ -337,7 +345,8 @@ class NotificationUtils @Inject constructor(private val context: Context,
                         IconCompat.createWithResource(context, R.drawable.ic_call_hangup)
                                 .setTint(ThemeUtils.getColor(context, R.attr.colorError)),
                         getActionText(R.string.call_notification_reject, R.attr.colorError),
-                        rejectCallPendingIntent)
+                        rejectCallPendingIntent
+                )
         )
 
         builder.addAction(
@@ -380,7 +389,12 @@ class NotificationUtils @Inject constructor(private val context: Context,
             flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
             data = createIgnoredUri(call.callId)
         }
-        val contentPendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), contentIntent, 0)
+        val contentPendingIntent = PendingIntent.getActivity(
+                context,
+                System.currentTimeMillis().toInt(),
+                contentIntent,
+                PendingIntentCompat.FLAG_IMMUTABLE
+        )
 
         val rejectCallPendingIntent = buildRejectCallPendingIntent(call.callId)
 
@@ -389,7 +403,8 @@ class NotificationUtils @Inject constructor(private val context: Context,
                         IconCompat.createWithResource(context, R.drawable.ic_call_hangup)
                                 .setTint(ThemeUtils.getColor(context, R.attr.colorError)),
                         getActionText(R.string.call_notification_hangup, R.attr.colorError),
-                        rejectCallPendingIntent)
+                        rejectCallPendingIntent
+                )
         )
         builder.setContentIntent(contentPendingIntent)
 
@@ -430,13 +445,14 @@ class NotificationUtils @Inject constructor(private val context: Context,
                         IconCompat.createWithResource(context, R.drawable.ic_call_hangup)
                                 .setTint(ThemeUtils.getColor(context, R.attr.colorError)),
                         getActionText(R.string.call_notification_hangup, R.attr.colorError),
-                        rejectCallPendingIntent)
+                        rejectCallPendingIntent
+                )
         )
 
         val contentPendingIntent = TaskStackBuilder.create(context)
                 .addNextIntentWithParentStack(HomeActivity.newIntent(context))
                 .addNextIntent(VectorCallActivity.newIntent(context, call, null))
-                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
+                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
 
         builder.setContentIntent(contentPendingIntent)
 
@@ -452,7 +468,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
                 context,
                 System.currentTimeMillis().toInt(),
                 rejectCallActionReceiver,
-                PendingIntent.FLAG_UPDATE_CURRENT
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
         )
     }
 
@@ -498,7 +514,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
         val contentPendingIntent = TaskStackBuilder.create(context)
                 .addNextIntentWithParentStack(HomeActivity.newIntent(context))
                 .addNextIntent(RoomDetailActivity.newIntent(context, RoomDetailArgs(callInformation.nativeRoomId)))
-                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
+                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
 
         builder.setContentIntent(contentPendingIntent)
         return builder.build()
@@ -516,7 +532,10 @@ class NotificationUtils @Inject constructor(private val context: Context,
                         addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                     }
                     PendingIntent.getActivity(
-                            context, System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT
+                            context,
+                            System.currentTimeMillis().toInt(),
+                            intent,
+                            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
                     ).let {
                         setContentIntent(it)
                     }
@@ -588,8 +607,12 @@ class NotificationUtils @Inject constructor(private val context: Context,
                     markRoomReadIntent.action = MARK_ROOM_READ_ACTION
                     markRoomReadIntent.data = createIgnoredUri(roomInfo.roomId)
                     markRoomReadIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomInfo.roomId)
-                    val markRoomReadPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(), markRoomReadIntent,
-                            PendingIntent.FLAG_UPDATE_CURRENT)
+                    val markRoomReadPendingIntent = PendingIntent.getBroadcast(
+                            context,
+                            System.currentTimeMillis().toInt(),
+                            markRoomReadIntent,
+                            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+                    )
 
                     NotificationCompat.Action.Builder(R.drawable.ic_material_done_all_white,
                             stringProvider.getString(R.string.action_mark_room_read), markRoomReadPendingIntent)
@@ -625,8 +648,12 @@ class NotificationUtils @Inject constructor(private val context: Context,
                     val intent = Intent(context, NotificationBroadcastReceiver::class.java)
                     intent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomInfo.roomId)
                     intent.action = DISMISS_ROOM_NOTIF_ACTION
-                    val pendingIntent = PendingIntent.getBroadcast(context.applicationContext,
-                            System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
+                    val pendingIntent = PendingIntent.getBroadcast(
+                            context.applicationContext,
+                            System.currentTimeMillis().toInt(),
+                            intent,
+                            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+                    )
                     setDeleteIntent(pendingIntent)
                 }
                 .setTicker(tickerText)
@@ -643,7 +670,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
 
         return NotificationCompat.Builder(context, channelID)
                 .setOnlyAlertOnce(true)
-                .setContentTitle(stringProvider.getString(R.string.app_name))
+                .setContentTitle(inviteNotifiableEvent.roomName ?: stringProvider.getString(R.string.app_name))
                 .setContentText(inviteNotifiableEvent.description)
                 .setGroup(stringProvider.getString(R.string.app_name))
                 .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
@@ -656,31 +683,41 @@ class NotificationUtils @Inject constructor(private val context: Context,
                     rejectIntent.action = REJECT_ACTION
                     rejectIntent.data = createIgnoredUri("$roomId&$matrixId")
                     rejectIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
-                    val rejectIntentPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(), rejectIntent,
-                            PendingIntent.FLAG_UPDATE_CURRENT)
+                    val rejectIntentPendingIntent = PendingIntent.getBroadcast(
+                            context,
+                            System.currentTimeMillis().toInt(),
+                            rejectIntent,
+                            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+                    )
 
                     addAction(
                             R.drawable.vector_notification_reject_invitation,
                             stringProvider.getString(R.string.reject),
-                            rejectIntentPendingIntent)
+                            rejectIntentPendingIntent
+                    )
 
                     // offer to type a quick accept button
                     val joinIntent = Intent(context, NotificationBroadcastReceiver::class.java)
                     joinIntent.action = JOIN_ACTION
                     joinIntent.data = createIgnoredUri("$roomId&$matrixId")
                     joinIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
-                    val joinIntentPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(), joinIntent,
-                            PendingIntent.FLAG_UPDATE_CURRENT)
+                    val joinIntentPendingIntent = PendingIntent.getBroadcast(
+                            context,
+                            System.currentTimeMillis().toInt(),
+                            joinIntent,
+                            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+                    )
                     addAction(
                             R.drawable.vector_notification_accept_invitation,
                             stringProvider.getString(R.string.join),
-                            joinIntentPendingIntent)
+                            joinIntentPendingIntent
+                    )
 
                     val contentIntent = HomeActivity.newIntent(context, inviteNotificationRoomId = inviteNotifiableEvent.roomId)
                     contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
                     // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that
                     contentIntent.data = createIgnoredUri(inviteNotifiableEvent.eventId)
-                    setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, 0))
+                    setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, PendingIntentCompat.FLAG_IMMUTABLE))
 
                     if (inviteNotifiableEvent.noisy) {
                         // Compat
@@ -719,7 +756,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
                     contentIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
                     // pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that
                     contentIntent.data = createIgnoredUri(simpleNotifiableEvent.eventId)
-                    setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, 0))
+                    setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, PendingIntentCompat.FLAG_IMMUTABLE))
 
                     if (simpleNotifiableEvent.noisy) {
                         // Compat
@@ -746,14 +783,22 @@ class NotificationUtils @Inject constructor(private val context: Context,
         return TaskStackBuilder.create(context)
                 .addNextIntentWithParentStack(HomeActivity.newIntent(context))
                 .addNextIntent(roomIntentTap)
-                .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
+                .getPendingIntent(
+                        System.currentTimeMillis().toInt(),
+                        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+                )
     }
 
     private fun buildOpenHomePendingIntentForSummary(): PendingIntent {
         val intent = HomeActivity.newIntent(context, clearNotification = true)
         intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
         intent.data = createIgnoredUri("tapSummary")
-        return PendingIntent.getActivity(context, Random.nextInt(1000), intent, PendingIntent.FLAG_UPDATE_CURRENT)
+        return PendingIntent.getActivity(
+                context,
+                Random.nextInt(1000),
+                intent,
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+        )
     }
 
     /*
@@ -770,8 +815,13 @@ class NotificationUtils @Inject constructor(private val context: Context,
             intent.action = SMART_REPLY_ACTION
             intent.data = createIgnoredUri(roomId)
             intent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
-            return PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(), intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT)
+            return PendingIntent.getBroadcast(
+                    context,
+                    System.currentTimeMillis().toInt(),
+                    intent,
+                    // PendingIntents attached to actions with remote inputs must be mutable
+                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_MUTABLE
+            )
         } else {
             /*
             TODO
@@ -784,7 +834,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
                 // the action must be unique else the parameters are ignored
                 quickReplyIntent.action = QUICK_LAUNCH_ACTION
                 quickReplyIntent.data = createIgnoredUri($roomId")
-                return PendingIntent.getActivity(context, 0, quickReplyIntent, 0)
+                return PendingIntent.getActivity(context, 0, quickReplyIntent, PendingIntentCompat.FLAG_IMMUTABLE)
             }
              */
         }
@@ -838,8 +888,12 @@ class NotificationUtils @Inject constructor(private val context: Context,
         val intent = Intent(context, NotificationBroadcastReceiver::class.java)
         intent.action = DISMISS_SUMMARY_ACTION
         intent.data = createIgnoredUri("deleteSummary")
-        return PendingIntent.getBroadcast(context.applicationContext,
-                0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+        return PendingIntent.getBroadcast(
+                context.applicationContext,
+                0,
+                intent,
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
+        )
     }
 
     fun showNotificationMessage(tag: String?, id: Int, notification: Notification) {
@@ -876,7 +930,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
                 context,
                 0,
                 testActionIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
         )
 
         notificationManager.notify(
diff --git a/vector/src/main/java/im/vector/app/features/notifications/ProcessedEvent.kt b/vector/src/main/java/im/vector/app/features/notifications/ProcessedEvent.kt
new file mode 100644
index 0000000000..8bd9819ca9
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/ProcessedEvent.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+data class ProcessedEvent<T>(
+        val type: Type,
+        val event: T
+) {
+
+    enum class Type {
+        KEEP,
+        REMOVE
+    }
+}
+
+fun <T> List<ProcessedEvent<T>>.onlyKeptEvents() = mapNotNull { processedEvent ->
+    processedEvent.event.takeIf { processedEvent.type == ProcessedEvent.Type.KEEP }
+}
diff --git a/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt b/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt
index 791803fa49..ff817520db 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/PushRuleTriggerListener.kt
@@ -16,10 +16,15 @@
 
 package im.vector.app.features.notifications
 
-import org.matrix.android.sdk.api.pushrules.Action
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.pushrules.PushEvents
 import org.matrix.android.sdk.api.pushrules.PushRuleService
+import org.matrix.android.sdk.api.pushrules.getActions
 import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.events.model.Event
 import timber.log.Timber
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -31,46 +36,36 @@ class PushRuleTriggerListener @Inject constructor(
 ) : PushRuleService.PushRuleListener {
 
     private var session: Session? = null
+    private val scope: CoroutineScope = CoroutineScope(SupervisorJob())
 
-    override fun onMatchRule(event: Event, actions: List<Action>) {
-        Timber.v("Push rule match for event ${event.eventId}")
-        val safeSession = session ?: return Unit.also {
-            Timber.e("Called without active session")
+    override fun onEvents(pushEvents: PushEvents) {
+        scope.launch {
+            session?.let { session ->
+                val notifiableEvents = createNotifiableEvents(pushEvents, session)
+                notificationDrawerManager.updateEvents { queuedEvents ->
+                    notifiableEvents.forEach { notifiableEvent ->
+                        queuedEvents.onNotifiableEventReceived(notifiableEvent)
+                    }
+                    queuedEvents.syncRoomEvents(roomsLeft = pushEvents.roomsLeft, roomsJoined = pushEvents.roomsJoined)
+                    queuedEvents.markRedacted(pushEvents.redactedEventIds)
+                }
+            } ?: Timber.e("Called without active session")
         }
+    }
 
-        val notificationAction = actions.toNotificationAction()
-        if (notificationAction.shouldNotify) {
-            val notifiableEvent = resolver.resolveEvent(event, safeSession)
-            if (notifiableEvent == null) {
-                Timber.v("## Failed to resolve event")
-                // TODO
+    private suspend fun createNotifiableEvents(pushEvents: PushEvents, session: Session): List<NotifiableEvent> {
+        return pushEvents.matchedEvents.mapNotNull { (event, pushRule) ->
+            Timber.v("Push rule match for event ${event.eventId}")
+            val action = pushRule.getActions().toNotificationAction()
+            if (action.shouldNotify) {
+                resolver.resolveEvent(event, session, isNoisy = !action.soundName.isNullOrBlank())
             } else {
-                notifiableEvent.noisy = !notificationAction.soundName.isNullOrBlank()
-                Timber.v("New event to notify")
-                notificationDrawerManager.onNotifiableEventReceived(notifiableEvent)
+                Timber.v("Matched push rule is set to not notify")
+                null
             }
-        } else {
-            Timber.v("Matched push rule is set to not notify")
         }
     }
 
-    override fun onRoomLeft(roomId: String) {
-        notificationDrawerManager.clearMessageEventOfRoom(roomId)
-        notificationDrawerManager.clearMemberShipNotificationForRoom(roomId)
-    }
-
-    override fun onRoomJoined(roomId: String) {
-        notificationDrawerManager.clearMemberShipNotificationForRoom(roomId)
-    }
-
-    override fun onEventRedacted(redactedEventId: String) {
-        notificationDrawerManager.onEventRedacted(redactedEventId)
-    }
-
-    override fun batchFinish() {
-        notificationDrawerManager.refreshNotificationDrawer()
-    }
-
     fun startWithSession(session: Session) {
         if (this.session != null) {
             stop()
@@ -80,6 +75,7 @@ class PushRuleTriggerListener @Inject constructor(
     }
 
     fun stop() {
+        scope.coroutineContext.cancelChildren(CancellationException("PushRuleTriggerListener stopping"))
         session?.removePushRuleListener(this)
         session = null
         notificationDrawerManager.clearAllEvents()
diff --git a/vector/src/main/java/im/vector/app/features/notifications/RoomGroupMessageCreator.kt b/vector/src/main/java/im/vector/app/features/notifications/RoomGroupMessageCreator.kt
new file mode 100644
index 0000000000..b57c81f686
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/RoomGroupMessageCreator.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import android.content.Context
+import android.graphics.Bitmap
+import androidx.core.app.NotificationCompat
+import androidx.core.app.Person
+import im.vector.app.R
+import im.vector.app.core.resources.StringProvider
+import me.gujun.android.span.Span
+import me.gujun.android.span.span
+import timber.log.Timber
+import javax.inject.Inject
+
+class RoomGroupMessageCreator @Inject constructor(
+        private val iconLoader: IconLoader,
+        private val bitmapLoader: BitmapLoader,
+        private val stringProvider: StringProvider,
+        private val notificationUtils: NotificationUtils,
+        private val appContext: Context
+) {
+
+    fun createRoomMessage(events: List<NotifiableMessageEvent>, roomId: String, userDisplayName: String, userAvatarUrl: String?): RoomNotification.Message {
+        val firstKnownRoomEvent = events[0]
+        val roomName = firstKnownRoomEvent.roomName ?: firstKnownRoomEvent.senderName ?: ""
+        val roomIsGroup = !firstKnownRoomEvent.roomIsDirect
+        val style = NotificationCompat.MessagingStyle(Person.Builder()
+                .setName(userDisplayName)
+                .setIcon(iconLoader.getUserIcon(userAvatarUrl))
+                .setKey(firstKnownRoomEvent.matrixID)
+                .build()
+        ).also {
+            it.conversationTitle = roomName.takeIf { roomIsGroup }
+            it.isGroupConversation = roomIsGroup
+            it.addMessagesFromEvents(events)
+        }
+
+        val tickerText = if (roomIsGroup) {
+            stringProvider.getString(R.string.notification_ticker_text_group, roomName, events.last().senderName, events.last().description)
+        } else {
+            stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderName, events.last().description)
+        }
+
+        val largeBitmap = getRoomBitmap(events)
+
+        val lastMessageTimestamp = events.last().timestamp
+        val smartReplyErrors = events.filter { it.isSmartReplyError() }
+        val messageCount = (events.size - smartReplyErrors.size)
+        val meta = RoomNotification.Message.Meta(
+                summaryLine = createRoomMessagesGroupSummaryLine(events, roomName, roomIsDirect = !roomIsGroup),
+                messageCount = messageCount,
+                latestTimestamp = lastMessageTimestamp,
+                roomId = roomId,
+                shouldBing = events.any { it.noisy }
+        )
+        return RoomNotification.Message(
+                notificationUtils.buildMessagesListNotification(
+                        style,
+                        RoomEventGroupInfo(roomId, roomName, isDirect = !roomIsGroup).also {
+                            it.hasSmartReplyError = smartReplyErrors.isNotEmpty()
+                            it.shouldBing = meta.shouldBing
+                            it.customSound = events.last().soundName
+                        },
+                        largeIcon = largeBitmap,
+                        lastMessageTimestamp,
+                        userDisplayName,
+                        tickerText
+                ),
+                meta
+        )
+    }
+
+    private fun NotificationCompat.MessagingStyle.addMessagesFromEvents(events: List<NotifiableMessageEvent>) {
+        events.forEach { event ->
+            val senderPerson = if (event.outGoingMessage) {
+                null
+            } else {
+                Person.Builder()
+                        .setName(event.senderName)
+                        .setIcon(iconLoader.getUserIcon(event.senderAvatarPath))
+                        .setKey(event.senderId)
+                        .build()
+            }
+            when {
+                event.isSmartReplyError() -> addMessage(stringProvider.getString(R.string.notification_inline_reply_failed), event.timestamp, senderPerson)
+                else                      -> {
+                    val message = NotificationCompat.MessagingStyle.Message(event.body, event.timestamp, senderPerson).also { message ->
+                        event.imageUri?.let {
+                            message.setData("image/", it)
+                        }
+                    }
+                    addMessage(message)
+                }
+            }
+        }
+    }
+
+    private fun createRoomMessagesGroupSummaryLine(events: List<NotifiableMessageEvent>, roomName: String, roomIsDirect: Boolean): CharSequence {
+        return try {
+            when (events.size) {
+                1    -> createFirstMessageSummaryLine(events.first(), roomName, roomIsDirect)
+                else -> {
+                    stringProvider.getQuantityString(
+                            R.plurals.notification_compat_summary_line_for_room,
+                            events.size,
+                            roomName,
+                            events.size
+                    )
+                }
+            }
+        } catch (e: Throwable) {
+            // String not found or bad format
+            Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER failed to resolve string")
+            roomName
+        }
+    }
+
+    private fun createFirstMessageSummaryLine(event: NotifiableMessageEvent, roomName: String, roomIsDirect: Boolean): Span {
+        return if (roomIsDirect) {
+            span {
+                span {
+                    textStyle = "bold"
+                    +String.format("%s: ", event.senderName)
+                }
+                +(event.description)
+            }
+        } else {
+            span {
+                span {
+                    textStyle = "bold"
+                    +String.format("%s: %s ", roomName, event.senderName)
+                }
+                +(event.description)
+            }
+        }
+    }
+
+    private fun getRoomBitmap(events: List<NotifiableMessageEvent>): Bitmap? {
+        // Use the last event (most recent?)
+        return events.lastOrNull()
+                ?.roomAvatarPath
+                ?.let { bitmapLoader.getRoomBitmap(it) }
+    }
+}
+
+private fun NotifiableMessageEvent.isSmartReplyError() = outGoingMessage && outGoingMessageFailed
diff --git a/vector/src/main/java/im/vector/app/features/notifications/SimpleNotifiableEvent.kt b/vector/src/main/java/im/vector/app/features/notifications/SimpleNotifiableEvent.kt
index 2f74737ba2..8c72372204 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/SimpleNotifiableEvent.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/SimpleNotifiableEvent.kt
@@ -15,21 +15,16 @@
  */
 package im.vector.app.features.notifications
 
-import androidx.core.app.NotificationCompat
-
 data class SimpleNotifiableEvent(
-        override var matrixID: String?,
+        val matrixID: String?,
         override val eventId: String,
         override val editedEventId: String?,
-        override var noisy: Boolean,
-        override val title: String,
-        override val description: String,
-        override val type: String?,
-        override val timestamp: Long,
-        override var soundName: String?,
-        override var isPushGatewayEvent: Boolean = false) : NotifiableEvent {
-
-    override var hasBeenDisplayed: Boolean = false
-    override var isRedacted: Boolean = false
-    override var lockScreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
-}
+        val noisy: Boolean,
+        val title: String,
+        val description: String,
+        val type: String?,
+        val timestamp: Long,
+        val soundName: String?,
+        override var canBeReplaced: Boolean,
+        override val isRedacted: Boolean = false
+) : NotifiableEvent
diff --git a/vector/src/main/java/im/vector/app/features/notifications/SummaryGroupMessageCreator.kt b/vector/src/main/java/im/vector/app/features/notifications/SummaryGroupMessageCreator.kt
new file mode 100644
index 0000000000..91163434c2
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/notifications/SummaryGroupMessageCreator.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import android.app.Notification
+import androidx.core.app.NotificationCompat
+import im.vector.app.R
+import im.vector.app.core.resources.StringProvider
+import javax.inject.Inject
+
+/**
+ * ======== Build summary notification =========
+ * On Android 7.0 (API level 24) and higher, the system automatically builds a summary for
+ * your group using snippets of text from each notification. The user can expand this
+ * notification to see each separate notification.
+ * To support older versions, which cannot show a nested group of notifications,
+ * you must create an extra notification that acts as the summary.
+ * This appears as the only notification and the system hides all the others.
+ * So this summary should include a snippet from all the other notifications,
+ * which the user can tap to open your app.
+ * The behavior of the group summary may vary on some device types such as wearables.
+ * To ensure the best experience on all devices and versions, always include a group summary when you create a group
+ * https://developer.android.com/training/notify-user/group
+ */
+class SummaryGroupMessageCreator @Inject constructor(
+        private val stringProvider: StringProvider,
+        private val notificationUtils: NotificationUtils
+) {
+
+    fun createSummaryNotification(roomNotifications: List<RoomNotification.Message.Meta>,
+                                  invitationNotifications: List<OneShotNotification.Append.Meta>,
+                                  simpleNotifications: List<OneShotNotification.Append.Meta>,
+                                  useCompleteNotificationFormat: Boolean): Notification {
+        val summaryInboxStyle = NotificationCompat.InboxStyle().also { style ->
+            roomNotifications.forEach { style.addLine(it.summaryLine) }
+            invitationNotifications.forEach { style.addLine(it.summaryLine) }
+            simpleNotifications.forEach { style.addLine(it.summaryLine) }
+        }
+
+        val summaryIsNoisy = roomNotifications.any { it.shouldBing } ||
+                invitationNotifications.any { it.isNoisy } ||
+                simpleNotifications.any { it.isNoisy }
+
+        val messageCount = roomNotifications.fold(initial = 0) { acc, current -> acc + current.messageCount }
+
+        val lastMessageTimestamp = roomNotifications.lastOrNull()?.latestTimestamp
+                ?: invitationNotifications.lastOrNull()?.timestamp
+                ?: simpleNotifications.last().timestamp
+
+        // FIXME roomIdToEventMap.size is not correct, this is the number of rooms
+        val nbEvents = roomNotifications.size + simpleNotifications.size
+        val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
+        summaryInboxStyle.setBigContentTitle(sumTitle)
+                // TODO get latest event?
+                .setSummaryText(stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents))
+        return if (useCompleteNotificationFormat) {
+            notificationUtils.buildSummaryListNotification(
+                    summaryInboxStyle,
+                    sumTitle,
+                    noisy = summaryIsNoisy,
+                    lastMessageTimestamp = lastMessageTimestamp
+            )
+        } else {
+            processSimpleGroupSummary(
+                    summaryIsNoisy,
+                    messageCount,
+                    simpleNotifications.size,
+                    invitationNotifications.size,
+                    roomNotifications.size,
+                    lastMessageTimestamp
+            )
+        }
+    }
+
+    private fun processSimpleGroupSummary(summaryIsNoisy: Boolean,
+                                          messageEventsCount: Int,
+                                          simpleEventsCount: Int,
+                                          invitationEventsCount: Int,
+                                          roomCount: Int,
+                                          lastMessageTimestamp: Long): Notification {
+        // Add the simple events as message (?)
+        val messageNotificationCount = messageEventsCount + simpleEventsCount
+
+        val privacyTitle = if (invitationEventsCount > 0) {
+            val invitationsStr = stringProvider.getQuantityString(R.plurals.notification_invitations, invitationEventsCount, invitationEventsCount)
+            if (messageNotificationCount > 0) {
+                // Invitation and message
+                val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification,
+                        messageNotificationCount, messageNotificationCount)
+                if (roomCount > 1) {
+                    // In several rooms
+                    val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms,
+                            roomCount, roomCount)
+                    stringProvider.getString(
+                            R.string.notification_unread_notified_messages_in_room_and_invitation,
+                            messageStr,
+                            roomStr,
+                            invitationsStr
+                    )
+                } else {
+                    // In one room
+                    stringProvider.getString(
+                            R.string.notification_unread_notified_messages_and_invitation,
+                            messageStr,
+                            invitationsStr
+                    )
+                }
+            } else {
+                // Only invitation
+                invitationsStr
+            }
+        } else {
+            // No invitation, only messages
+            val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification,
+                    messageNotificationCount, messageNotificationCount)
+            if (roomCount > 1) {
+                // In several rooms
+                val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms, roomCount, roomCount)
+                stringProvider.getString(R.string.notification_unread_notified_messages_in_room, messageStr, roomStr)
+            } else {
+                // In one room
+                messageStr
+            }
+        }
+        return notificationUtils.buildSummaryListNotification(
+                style = null,
+                compatSummary = privacyTitle,
+                noisy = summaryIsNoisy,
+                lastMessageTimestamp = lastMessageTimestamp
+        )
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt
index 90bcee3d04..40cc0b3e13 100644
--- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt
+++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt
@@ -18,6 +18,7 @@ package im.vector.app.features.permalink
 
 import android.content.Context
 import android.net.Uri
+import androidx.core.net.toUri
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.extensions.isIgnored
@@ -79,15 +80,14 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
         return when (permalinkData) {
             is PermalinkData.RoomLink            -> {
                 val roomId = permalinkData.getRoomId()
-                if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId, rawLink) != true) {
-                    openRoom(
-                            context = context,
-                            roomId = roomId,
-                            permalinkData = permalinkData,
-                            rawLink = rawLink,
-                            buildTask = buildTask
-                    )
-                }
+                openRoom(
+                        navigationInterceptor,
+                        context = context,
+                        roomId = roomId,
+                        permalinkData = permalinkData,
+                        rawLink = rawLink,
+                        buildTask = buildTask
+                )
                 true
             }
             is PermalinkData.GroupLink           -> {
@@ -119,9 +119,8 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
 
     private fun isPermalinkSupported(context: Context, url: String): Boolean {
         return url.startsWith(PermalinkService.MATRIX_TO_URL_BASE) ||
-                context.resources.getStringArray(R.array.permalink_supported_hosts).any {
-                    url.startsWith(it)
-                }
+                context.resources.getStringArray(R.array.permalink_supported_hosts)
+                        .any { url.toUri().host == it }
     }
 
     private suspend fun PermalinkData.RoomLink.getRoomId(): String? {
@@ -146,6 +145,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
      * Open room either joined, or not
      */
     private fun openRoom(
+            navigationInterceptor: NavigationInterceptor?,
             context: Context,
             roomId: String?,
             permalinkData: PermalinkData.RoomLink,
@@ -167,7 +167,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
             membership?.isActive().orFalse() -> {
                 if (!isSpace && membership == Membership.JOIN) {
                     // If it's a room you're in, let's just open it, you can tap back if needed
-                    navigator.openRoom(context, roomId, eventId, buildTask)
+                    navigationInterceptor.openJoinedRoomScreen(buildTask, roomId, eventId, rawLink, context)
                 } else {
                     // maybe open space preview navigator.openSpacePreview(context, roomId)? if already joined?
                     navigator.openMatrixToBottomSheet(context, rawLink.toString())
@@ -180,6 +180,12 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
         }
     }
 
+    private fun NavigationInterceptor?.openJoinedRoomScreen(buildTask: Boolean, roomId: String, eventId: String?, rawLink: Uri, context: Context) {
+        if (this?.navToRoom(roomId, eventId, rawLink) != true) {
+            navigator.openRoom(context, roomId, eventId, buildTask)
+        }
+    }
+
     companion object {
         const val MATRIX_TO_CUSTOM_SCHEME_URL_BASE = "element://"
         const val ROOM_LINK_PREFIX = "${MATRIX_TO_CUSTOM_SCHEME_URL_BASE}room/"
diff --git a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt
index 430be6bc1f..0978f0d5b5 100644
--- a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt
@@ -20,12 +20,14 @@ import android.content.Context
 import android.content.Intent
 import com.airbnb.mvrx.Mavericks
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 
+@AndroidEntryPoint
 class PinActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable, UnlockedActivity {
 
     companion object {
diff --git a/vector/src/main/java/im/vector/app/features/pin/PinCodeStore.kt b/vector/src/main/java/im/vector/app/features/pin/PinCodeStore.kt
index fb7c6897e2..d3632edbca 100644
--- a/vector/src/main/java/im/vector/app/features/pin/PinCodeStore.kt
+++ b/vector/src/main/java/im/vector/app/features/pin/PinCodeStore.kt
@@ -25,6 +25,7 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.extensions.orFalse
 import javax.inject.Inject
+import javax.inject.Singleton
 import kotlin.coroutines.resume
 import kotlin.coroutines.suspendCoroutine
 
@@ -56,26 +57,40 @@ interface PinCodeStore {
      * Will reset the counters
      */
     fun resetCounters()
+
+    fun addListener(listener: PinCodeStoreListener)
+    fun removeListener(listener: PinCodeStoreListener)
 }
 
-class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences: SharedPreferences) : PinCodeStore {
+interface PinCodeStoreListener {
+    fun onPinSetUpChange(isConfigured: Boolean)
+}
 
-    override suspend fun storeEncodedPin(encodePin: String) = withContext(Dispatchers.IO) {
-        sharedPreferences.edit {
-            putString(ENCODED_PIN_CODE_KEY, encodePin)
+@Singleton
+class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences: SharedPreferences) : PinCodeStore {
+    private val listeners = mutableSetOf<PinCodeStoreListener>()
+
+    override suspend fun storeEncodedPin(encodePin: String) {
+        withContext(Dispatchers.IO) {
+            sharedPreferences.edit {
+                putString(ENCODED_PIN_CODE_KEY, encodePin)
+            }
         }
+        listeners.forEach { it.onPinSetUpChange(isConfigured = true) }
     }
 
-    override suspend fun deleteEncodedPin() = withContext(Dispatchers.IO) {
-        // Also reset the counters
-        resetCounters()
-        sharedPreferences.edit {
-            remove(ENCODED_PIN_CODE_KEY)
+    override suspend fun deleteEncodedPin() {
+        withContext(Dispatchers.IO) {
+            // Also reset the counters
+            resetCounters()
+            sharedPreferences.edit {
+                remove(ENCODED_PIN_CODE_KEY)
+            }
+            awaitPinCodeCallback<Boolean> {
+                PFSecurityManager.getInstance().pinCodeHelper.delete(it)
+            }
         }
-        awaitPinCodeCallback<Boolean> {
-            PFSecurityManager.getInstance().pinCodeHelper.delete(it)
-        }
-        return@withContext
+        listeners.forEach { it.onPinSetUpChange(isConfigured = false) }
     }
 
     override fun getEncodedPin(): String? {
@@ -124,6 +139,14 @@ class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences:
         }
     }
 
+    override fun addListener(listener: PinCodeStoreListener) {
+        listeners.add(listener)
+    }
+
+    override fun removeListener(listener: PinCodeStoreListener) {
+        listeners.remove(listener)
+    }
+
     private suspend inline fun <T> awaitPinCodeCallback(crossinline callback: (PFPinCodeHelperCallback<T>) -> Unit) = suspendCoroutine<PFResult<T>> { cont ->
         callback(PFPinCodeHelperCallback<T> { result -> cont.resume(result) })
     }
diff --git a/vector/src/main/java/im/vector/app/features/pin/PinLocker.kt b/vector/src/main/java/im/vector/app/features/pin/PinLocker.kt
index 9c55b88805..f848a3174e 100644
--- a/vector/src/main/java/im/vector/app/features/pin/PinLocker.kt
+++ b/vector/src/main/java/im/vector/app/features/pin/PinLocker.kt
@@ -17,11 +17,10 @@
 package im.vector.app.features.pin
 
 import android.os.SystemClock
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.OnLifecycleEvent
 import im.vector.app.features.settings.VectorPreferences
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.launch
@@ -41,7 +40,7 @@ private const val PERIOD_OF_GRACE_IN_MS = 2 * 60 * 1000L
 class PinLocker @Inject constructor(
         private val pinCodeStore: PinCodeStore,
         private val vectorPreferences: VectorPreferences
-) : LifecycleObserver {
+) : DefaultLifecycleObserver {
 
     enum class State {
         // App is locked, can be unlock
@@ -87,16 +86,14 @@ class PinLocker @Inject constructor(
         computeState()
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
-    fun entersForeground() {
+    override fun onResume(owner: LifecycleOwner) {
         val timeElapsedSinceBackground = SystemClock.elapsedRealtime() - entersBackgroundTs
         shouldBeLocked = shouldBeLocked || timeElapsedSinceBackground >= getGracePeriod()
         Timber.v("App enters foreground after $timeElapsedSinceBackground ms spent in background shouldBeLocked: $shouldBeLocked")
         computeState()
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
-    fun entersBackground() {
+    override fun onPause(owner: LifecycleOwner) {
         Timber.v("App enters background")
         entersBackgroundTs = SystemClock.elapsedRealtime()
     }
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollAction.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollAction.kt
new file mode 100644
index 0000000000..182750fbd2
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollAction.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import im.vector.app.core.platform.VectorViewModelAction
+
+sealed class CreatePollAction : VectorViewModelAction {
+    data class OnQuestionChanged(val question: String) : CreatePollAction()
+    data class OnOptionChanged(val index: Int, val option: String) : CreatePollAction()
+    data class OnDeleteOption(val index: Int) : CreatePollAction()
+    object OnAddOption : CreatePollAction()
+    object OnCreatePoll : CreatePollAction()
+}
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollActivity.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollActivity.kt
new file mode 100644
index 0000000000..fc830ddae9
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollActivity.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.SimpleFragmentActivity
+
+@AndroidEntryPoint
+class CreatePollActivity : SimpleFragmentActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        views.toolbar.visibility = View.GONE
+
+        val createPollArgs: CreatePollArgs? = intent?.extras?.getParcelable(EXTRA_CREATE_POLL_ARGS)
+
+        if (isFirstCreation()) {
+            addFragment(
+                    R.id.container,
+                    CreatePollFragment::class.java,
+                    createPollArgs
+            )
+        }
+    }
+
+    companion object {
+
+        private const val EXTRA_CREATE_POLL_ARGS = "EXTRA_CREATE_POLL_ARGS"
+
+        fun getIntent(context: Context, createPollArgs: CreatePollArgs): Intent {
+            return Intent(context, CreatePollActivity::class.java).apply {
+                putExtra(EXTRA_CREATE_POLL_ARGS, createPollArgs)
+            }
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollController.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollController.kt
new file mode 100644
index 0000000000..515f59a38c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollController.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import android.view.Gravity
+import android.view.inputmethod.EditorInfo
+import com.airbnb.epoxy.EpoxyController
+import im.vector.app.R
+import im.vector.app.core.resources.ColorProvider
+import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.ui.list.ItemStyle
+import im.vector.app.core.ui.list.genericButtonItem
+import im.vector.app.core.ui.list.genericItem
+import im.vector.app.features.form.formEditTextItem
+import im.vector.app.features.form.formEditTextWithDeleteItem
+import javax.inject.Inject
+
+class CreatePollController @Inject constructor(
+        private val stringProvider: StringProvider,
+        private val colorProvider: ColorProvider
+) : EpoxyController() {
+
+    private var state: CreatePollViewState? = null
+    var callback: Callback? = null
+
+    fun setData(state: CreatePollViewState) {
+        this.state = state
+        requestModelBuild()
+    }
+
+    override fun buildModels() {
+        val currentState = state ?: return
+        val host = this
+
+        genericItem {
+            id("question_title")
+            style(ItemStyle.BIG_TEXT)
+            title(host.stringProvider.getString(R.string.create_poll_question_title))
+        }
+
+        val questionImeAction = if (currentState.options.isEmpty()) EditorInfo.IME_ACTION_DONE else EditorInfo.IME_ACTION_NEXT
+
+        formEditTextItem {
+            id("question")
+            value(currentState.question)
+            hint(host.stringProvider.getString(R.string.create_poll_question_hint))
+            singleLine(true)
+            imeOptions(questionImeAction)
+            maxLength(500)
+            onTextChange {
+                host.callback?.onQuestionChanged(it)
+            }
+        }
+
+        genericItem {
+            id("options_title")
+            style(ItemStyle.BIG_TEXT)
+            title(host.stringProvider.getString(R.string.create_poll_options_title))
+        }
+
+        currentState.options.forEachIndexed { index, option ->
+            val imeOptions = if (index == currentState.options.size - 1) EditorInfo.IME_ACTION_DONE else EditorInfo.IME_ACTION_NEXT
+            formEditTextWithDeleteItem {
+                id("option_$index")
+                value(option)
+                hint(host.stringProvider.getString(R.string.create_poll_options_hint, (index + 1)))
+                singleLine(true)
+                imeOptions(imeOptions)
+                onTextChange {
+                    host.callback?.onOptionChanged(index, it)
+                }
+                onDeleteClicked {
+                    host.callback?.onDeleteOption(index)
+                }
+            }
+        }
+
+        if (currentState.canAddMoreOptions) {
+            genericButtonItem {
+                id("add_option")
+                text(host.stringProvider.getString(R.string.create_poll_add_option))
+                textColor(host.colorProvider.getColor(R.color.palette_element_green))
+                gravity(Gravity.START)
+                bold(true)
+                buttonClickAction {
+                    host.callback?.onAddOption()
+                }
+            }
+        }
+    }
+
+    interface Callback {
+        fun onQuestionChanged(question: String)
+        fun onOptionChanged(index: Int, option: String)
+        fun onDeleteOption(index: Int)
+        fun onAddOption()
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollFragment.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollFragment.kt
new file mode 100644
index 0000000000..dc82579f15
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollFragment.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import android.os.Bundle
+import android.os.Parcelable
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import com.airbnb.mvrx.activityViewModel
+import com.airbnb.mvrx.withState
+import im.vector.app.R
+import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.platform.VectorBaseFragment
+import im.vector.app.databinding.FragmentCreatePollBinding
+import kotlinx.parcelize.Parcelize
+import javax.inject.Inject
+
+@Parcelize
+data class CreatePollArgs(
+        val roomId: String,
+) : Parcelable
+
+class CreatePollFragment @Inject constructor(
+        private val controller: CreatePollController
+) : VectorBaseFragment<FragmentCreatePollBinding>(), CreatePollController.Callback {
+
+    private val viewModel: CreatePollViewModel by activityViewModel()
+
+    override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentCreatePollBinding {
+        return FragmentCreatePollBinding.inflate(inflater, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        vectorBaseActivity.setSupportActionBar(views.createPollToolbar)
+
+        views.createPollRecyclerView.configureWith(controller, disableItemAnimation = true)
+        controller.callback = this
+
+        views.createPollClose.debouncedClicks {
+            requireActivity().finish()
+        }
+
+        views.createPollButton.debouncedClicks {
+            viewModel.handle(CreatePollAction.OnCreatePoll)
+        }
+
+        viewModel.onEach(CreatePollViewState::canCreatePoll) { canCreatePoll ->
+            views.createPollButton.isEnabled = canCreatePoll
+        }
+
+        viewModel.observeViewEvents {
+            when (it) {
+                CreatePollViewEvents.Success                  -> handleSuccess()
+                CreatePollViewEvents.EmptyQuestionError       -> handleEmptyQuestionError()
+                is CreatePollViewEvents.NotEnoughOptionsError -> handleNotEnoughOptionsError(it.requiredOptionsCount)
+            }
+        }
+    }
+
+    override fun invalidate() = withState(viewModel) {
+        controller.setData(it)
+    }
+
+    override fun onQuestionChanged(question: String) {
+        viewModel.handle(CreatePollAction.OnQuestionChanged(question))
+    }
+
+    override fun onOptionChanged(index: Int, option: String) {
+        viewModel.handle(CreatePollAction.OnOptionChanged(index, option))
+    }
+
+    override fun onDeleteOption(index: Int) {
+        viewModel.handle(CreatePollAction.OnDeleteOption(index))
+    }
+
+    override fun onAddOption() {
+        viewModel.handle(CreatePollAction.OnAddOption)
+        // Scroll to bottom to show "Add Option" button
+        views.createPollRecyclerView.apply {
+            postDelayed({
+                smoothScrollToPosition(adapter?.itemCount?.minus(1) ?: 0)
+            }, 100)
+        }
+    }
+
+    private fun handleSuccess() {
+        requireActivity().finish()
+    }
+
+    private fun handleEmptyQuestionError() {
+        renderToast(getString(R.string.create_poll_empty_question_error))
+    }
+
+    private fun handleNotEnoughOptionsError(requiredOptionsCount: Int) {
+        renderToast(
+                resources.getQuantityString(
+                        R.plurals.create_poll_not_enough_options_error,
+                        requiredOptionsCount,
+                        requiredOptionsCount
+                )
+        )
+    }
+
+    private fun renderToast(message: String) {
+        views.createPollToast.removeCallbacks(hideToastRunnable)
+        views.createPollToast.text = message
+        views.createPollToast.isVisible = true
+        views.createPollToast.postDelayed(hideToastRunnable, 2_000)
+    }
+
+    private val hideToastRunnable = Runnable {
+        views.createPollToast.isVisible = false
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewEvents.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewEvents.kt
new file mode 100644
index 0000000000..fa06deea6e
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewEvents.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import im.vector.app.core.platform.VectorViewEvents
+
+sealed class CreatePollViewEvents : VectorViewEvents {
+    object Success : CreatePollViewEvents()
+    object EmptyQuestionError : CreatePollViewEvents()
+    data class NotEnoughOptionsError(val requiredOptionsCount: Int) : CreatePollViewEvents()
+}
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt
new file mode 100644
index 0000000000..eb4b441f18
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewModel.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import com.airbnb.mvrx.MavericksViewModelFactory
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.platform.VectorViewModel
+import org.matrix.android.sdk.api.session.Session
+
+class CreatePollViewModel @AssistedInject constructor(
+        @Assisted private val initialState: CreatePollViewState,
+        session: Session
+) : VectorViewModel<CreatePollViewState, CreatePollAction, CreatePollViewEvents>(initialState) {
+
+    private val room = session.getRoom(initialState.roomId)!!
+
+    @AssistedFactory
+    interface Factory : MavericksAssistedViewModelFactory<CreatePollViewModel, CreatePollViewState> {
+        override fun create(initialState: CreatePollViewState): CreatePollViewModel
+    }
+
+    companion object : MavericksViewModelFactory<CreatePollViewModel, CreatePollViewState> by hiltMavericksViewModelFactory() {
+
+        const val MIN_OPTIONS_COUNT = 2
+        private const val MAX_OPTIONS_COUNT = 20
+    }
+
+    init {
+        observeState()
+    }
+
+    private fun observeState() {
+        onEach(
+                CreatePollViewState::question,
+                CreatePollViewState::options
+        ) { question, options ->
+            setState {
+                copy(
+                        canCreatePoll = canCreatePoll(question, options),
+                        canAddMoreOptions = options.size < MAX_OPTIONS_COUNT
+                )
+            }
+        }
+    }
+
+    override fun handle(action: CreatePollAction) {
+        when (action) {
+            CreatePollAction.OnCreatePoll         -> handleOnCreatePoll()
+            CreatePollAction.OnAddOption          -> handleOnAddOption()
+            is CreatePollAction.OnDeleteOption    -> handleOnDeleteOption(action.index)
+            is CreatePollAction.OnOptionChanged   -> handleOnOptionChanged(action.index, action.option)
+            is CreatePollAction.OnQuestionChanged -> handleOnQuestionChanged(action.question)
+        }
+    }
+
+    private fun handleOnCreatePoll() = withState { state ->
+        val nonEmptyOptions = state.options.filter { it.isNotEmpty() }
+        when {
+            state.question.isEmpty()                 -> {
+                _viewEvents.post(CreatePollViewEvents.EmptyQuestionError)
+            }
+            nonEmptyOptions.size < MIN_OPTIONS_COUNT -> {
+                _viewEvents.post(CreatePollViewEvents.NotEnoughOptionsError(requiredOptionsCount = MIN_OPTIONS_COUNT))
+            }
+            else                                     -> {
+                room.sendPoll(state.question, state.options)
+                _viewEvents.post(CreatePollViewEvents.Success)
+            }
+        }
+    }
+
+    private fun handleOnAddOption() {
+        setState {
+            val extendedOptions = options + ""
+            copy(
+                    options = extendedOptions
+            )
+        }
+    }
+
+    private fun handleOnDeleteOption(index: Int) {
+        setState {
+            val filteredOptions = options.filterIndexed { ind, _ -> ind != index }
+            copy(
+                    options = filteredOptions
+            )
+        }
+    }
+
+    private fun handleOnOptionChanged(index: Int, option: String) {
+        setState {
+            val changedOptions = options.mapIndexed { ind, s -> if (ind == index) option else s }
+            copy(
+                    options = changedOptions
+            )
+        }
+    }
+
+    private fun handleOnQuestionChanged(question: String) {
+        setState {
+            copy(
+                    question = question
+            )
+        }
+    }
+
+    private fun canCreatePoll(question: String, options: List<String>): Boolean {
+        return question.isNotEmpty() &&
+                options.filter { it.isNotEmpty() }.size >= MIN_OPTIONS_COUNT
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewState.kt b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewState.kt
new file mode 100644
index 0000000000..a9060cc89f
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/poll/create/CreatePollViewState.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.poll.create
+
+import com.airbnb.mvrx.MavericksState
+
+data class CreatePollViewState(
+        val roomId: String,
+        val question: String = "",
+        val options: List<String> = List(CreatePollViewModel.MIN_OPTIONS_COUNT) { "" },
+        val canCreatePoll: Boolean = false,
+        val canAddMoreOptions: Boolean = true
+) : MavericksState {
+
+    constructor(args: CreatePollArgs) : this(
+            roomId = args.roomId
+    )
+}
diff --git a/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt b/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt
index 767d6f1ba7..d8857b3be3 100644
--- a/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt
@@ -33,8 +33,8 @@ class PowerLevelsFlowFactory(private val room: Room) {
     fun createFlow(): Flow<PowerLevelsContent> {
         return room.flow()
                 .liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
-                .flowOn(Dispatchers.Default)
                 .mapOptional { it.content.toModel<PowerLevelsContent>() }
+                .flowOn(Dispatchers.Default)
                 .unwrap()
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt
index 13f989994a..7fb2f1f254 100644
--- a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt
@@ -23,22 +23,19 @@ import androidx.activity.result.ActivityResultLauncher
 import com.google.zxing.BarcodeFormat
 import com.google.zxing.Result
 import com.google.zxing.ResultMetadataType
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 
+@AndroidEntryPoint
 class QrCodeScannerActivity : VectorBaseActivity<ActivitySimpleBinding>() {
 
     override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
 
     override fun getCoordinatorLayout() = views.coordinatorLayout
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         if (isFirstCreation()) {
diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt
index d0245a7ce1..414f79e05d 100755
--- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt
@@ -25,27 +25,21 @@ import androidx.core.view.isVisible
 import androidx.core.widget.doOnTextChanged
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityBugReportBinding
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import timber.log.Timber
-import javax.inject.Inject
 
 /**
  * Form to send a bug report
  */
+@AndroidEntryPoint
 class BugReportActivity : VectorBaseActivity<ActivityBugReportBinding>() {
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding() = ActivityBugReportBinding.inflate(layoutInflater)
 
-    @Inject lateinit var bugReportViewModelFactory: BugReportViewModel.Factory
-
     private val viewModel: BugReportViewModel by viewModel()
 
     private var reportType: ReportType = ReportType.BUG_REPORT
diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt
index a1ec6b2e76..d0a1280868 100644
--- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt
@@ -16,14 +16,13 @@
 
 package im.vector.app.features.rageshake
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -36,18 +35,11 @@ class BugReportViewModel @AssistedInject constructor(
 ) : VectorViewModel<BugReportState, EmptyAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: BugReportState): BugReportViewModel
+    interface Factory : MavericksAssistedViewModelFactory<BugReportViewModel, BugReportState> {
+        override fun create(initialState: BugReportState): BugReportViewModel
     }
 
-    companion object : MavericksViewModelFactory<BugReportViewModel, BugReportState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: BugReportState): BugReportViewModel? {
-            val activity: BugReportActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.bugReportViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<BugReportViewModel, BugReportState>  by hiltMavericksViewModelFactory()
 
     init {
         fetchHomeserverVersion()
diff --git a/vector/src/main/java/im/vector/app/features/rageshake/RageShake.kt b/vector/src/main/java/im/vector/app/features/rageshake/RageShake.kt
index 48a6e8a679..b4dcb07349 100644
--- a/vector/src/main/java/im/vector/app/features/rageshake/RageShake.kt
+++ b/vector/src/main/java/im/vector/app/features/rageshake/RageShake.kt
@@ -19,8 +19,8 @@ package im.vector.app.features.rageshake
 import android.content.Context
 import android.hardware.Sensor
 import android.hardware.SensorManager
-import androidx.appcompat.app.AppCompatActivity
 import androidx.core.content.getSystemService
+import androidx.fragment.app.FragmentActivity
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.squareup.seismic.ShakeDetector
 import im.vector.app.R
@@ -30,7 +30,7 @@ import im.vector.app.features.settings.VectorPreferences
 import im.vector.app.features.settings.VectorSettingsActivity
 import javax.inject.Inject
 
-class RageShake @Inject constructor(private val activity: AppCompatActivity,
+class RageShake @Inject constructor(private val activity: FragmentActivity,
                                     private val bugReporter: BugReporter,
                                     private val navigator: Navigator,
                                     private val vectorPreferences: VectorPreferences) : ShakeDetector.Listener {
@@ -46,7 +46,7 @@ class RageShake @Inject constructor(private val activity: AppCompatActivity,
 
         shakeDetector = ShakeDetector(this).apply {
             setSensitivity(vectorPreferences.getRageshakeSensitivity())
-            start(sensorManager)
+            start(sensorManager, SensorManager.SENSOR_DELAY_GAME)
         }
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt
index e371aae096..d377c74ad7 100644
--- a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt
@@ -28,18 +28,18 @@ import androidx.core.view.isVisible
 import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.tabs.TabLayout
-import com.jakewharton.rxbinding3.widget.queryTextChanges
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.EmojiCompatFontProvider
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.observeEvent
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityEmojiReactionPickerBinding
 import im.vector.app.features.reactions.data.EmojiDataSource
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
-import timber.log.Timber
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.android.widget.queryTextChanges
 import javax.inject.Inject
 
 /**
@@ -47,6 +47,7 @@ import javax.inject.Inject
  * TODO: Loading indicator while getting emoji data source?
  * TODO: Finish Refactor to vector base activity
  */
+@AndroidEntryPoint
 class EmojiReactionPickerActivity : VectorBaseActivity<ActivityEmojiReactionPickerBinding>(),
         EmojiCompatFontProvider.FontProviderListener {
 
@@ -60,7 +61,6 @@ class EmojiReactionPickerActivity : VectorBaseActivity<ActivityEmojiReactionPick
 
     override fun getTitleRes() = R.string.title_activity_emoji_reaction_picker
 
-    @Inject lateinit var emojiSearchResultViewModelFactory: EmojiSearchResultViewModel.Factory
     @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider
     @Inject lateinit var emojiDataSource: EmojiDataSource
 
@@ -78,10 +78,6 @@ class EmojiReactionPickerActivity : VectorBaseActivity<ActivityEmojiReactionPick
         }
     }
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         configureToolbar(views.emojiPickerToolbar)
         emojiCompatFontProvider.let {
@@ -171,13 +167,11 @@ class EmojiReactionPickerActivity : VectorBaseActivity<ActivityEmojiReactionPick
             }
 
             searchView.queryTextChanges()
-                    .throttleWithTimeout(600, TimeUnit.MILLISECONDS)
-                    .doOnError { err -> Timber.e(err) }
-                    .observeOn(AndroidSchedulers.mainThread())
-                    .subscribe { query ->
+                    .throttleFirst(600)
+                    .onEach { query ->
                         onQueryText(query.toString())
                     }
-                    .disposeOnDestroy()
+                    .launchIn(lifecycleScope)
         }
         searchItem.expandActionView()
         return true
diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt
index ea04d6b25f..e1e52fdca1 100644
--- a/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt
@@ -15,14 +15,13 @@
  */
 package im.vector.app.features.reactions
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.reactions.data.EmojiDataSource
@@ -40,18 +39,11 @@ class EmojiSearchResultViewModel @AssistedInject constructor(
     VectorViewModel<EmojiSearchResultViewState, EmojiSearchAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: EmojiSearchResultViewState): EmojiSearchResultViewModel
+    interface Factory : MavericksAssistedViewModelFactory<EmojiSearchResultViewModel, EmojiSearchResultViewState> {
+        override fun create(initialState: EmojiSearchResultViewState): EmojiSearchResultViewModel
     }
 
-    companion object : MavericksViewModelFactory<EmojiSearchResultViewModel, EmojiSearchResultViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: EmojiSearchResultViewState): EmojiSearchResultViewModel? {
-            val activity: EmojiReactionPickerActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.emojiSearchResultViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<EmojiSearchResultViewModel, EmojiSearchResultViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: EmojiSearchAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/reactions/widget/ReactionButton.kt b/vector/src/main/java/im/vector/app/features/reactions/widget/ReactionButton.kt
index c342d6519d..2b4e9ee5ab 100644
--- a/vector/src/main/java/im/vector/app/features/reactions/widget/ReactionButton.kt
+++ b/vector/src/main/java/im/vector/app/features/reactions/widget/ReactionButton.kt
@@ -23,9 +23,9 @@ import android.view.View
 import android.widget.LinearLayout
 import androidx.core.content.ContextCompat
 import androidx.core.content.withStyledAttributes
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.EmojiCompatWrapper
 import im.vector.app.R
-import im.vector.app.core.di.HasScreenInjector
 import im.vector.app.core.utils.DimensionConverter
 import im.vector.app.core.utils.TextUtils
 import im.vector.app.databinding.ReactionButtonBinding
@@ -35,17 +35,12 @@ import javax.inject.Inject
  * An animated reaction button.
  * Displays a String reaction (emoji), with a count, and that can be selected or not (toggle)
  */
+@AndroidEntryPoint
 class ReactionButton @JvmOverloads constructor(context: Context,
                                                attrs: AttributeSet? = null,
                                                defStyleAttr: Int = 0) :
     LinearLayout(context, attrs, defStyleAttr), View.OnClickListener, View.OnLongClickListener {
 
-    init {
-        if (context is HasScreenInjector) {
-            context.injector().inject(this)
-        }
-    }
-
     @Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
 
     private val views: ReactionButtonBinding
diff --git a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt
index 44a6963a5d..d2ee3a56ec 100644
--- a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt
@@ -16,14 +16,13 @@
 
 package im.vector.app.features.room
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -55,21 +54,11 @@ class RequireActiveMembershipViewModel @AssistedInject constructor(
     VectorViewModel<RequireActiveMembershipViewState, RequireActiveMembershipAction, RequireActiveMembershipViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RequireActiveMembershipViewState): RequireActiveMembershipViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RequireActiveMembershipViewModel, RequireActiveMembershipViewState> {
+        override fun create(initialState: RequireActiveMembershipViewState): RequireActiveMembershipViewModel
     }
 
-    companion object : MavericksViewModelFactory<RequireActiveMembershipViewModel, RequireActiveMembershipViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RequireActiveMembershipViewState): RequireActiveMembershipViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RequireActiveMembershipViewModel, RequireActiveMembershipViewState> by hiltMavericksViewModelFactory()
 
     private val roomIdFlow = MutableStateFlow(Optional.from(initialState.roomId))
 
@@ -88,8 +77,8 @@ class RequireActiveMembershipViewModel @AssistedInject constructor(
                     room.flow()
                             .liveRoomSummary()
                             .unwrap()
-                            .flowOn(Dispatchers.Default)
                             .map { mapToLeftViewEvent(room, it) }
+                            .flowOn(Dispatchers.Default)
                 }
                 .unwrap()
                 .onEach { event ->
diff --git a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt
index dbf399bdf2..7a5363100f 100644
--- a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt
@@ -17,6 +17,7 @@
 package im.vector.app.features.room
 
 import com.airbnb.mvrx.MavericksState
+import im.vector.app.features.home.room.detail.RoomDetailArgs
 import im.vector.app.features.roommemberprofile.RoomMemberProfileArgs
 import im.vector.app.features.roomprofile.RoomProfileArgs
 
@@ -24,7 +25,7 @@ data class RequireActiveMembershipViewState(
         val roomId: String? = null
 ) : MavericksState {
 
-    // No constructor for RoomDetailArgs because of intent for Shortcut
+    constructor(args: RoomDetailArgs) : this(roomId = args.roomId)
 
     constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
 
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt
index b61583df55..be1523f4ab 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt
@@ -25,7 +25,6 @@ import android.view.ViewGroup
 import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.appcompat.queryTextChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
@@ -37,12 +36,14 @@ import im.vector.app.core.utils.toast
 import im.vector.app.databinding.FragmentPublicRoomsBinding
 import im.vector.app.features.permalink.NavigationInterceptor
 import im.vector.app.features.permalink.PermalinkHandler
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
+import reactivecircus.flowbinding.appcompat.queryTextChanges
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
 /**
@@ -79,11 +80,11 @@ class PublicRoomsFragment @Inject constructor(
         setupRecyclerView()
 
         views.publicRoomsFilter.queryTextChanges()
-                .debounce(500, TimeUnit.MILLISECONDS)
-                .subscribeBy {
+                .debounce(500)
+                .onEach {
                     viewModel.handle(RoomDirectoryAction.FilterWith(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.publicRoomsCreateNewRoom.debouncedClicks {
             sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoom)
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt
index 02bae82e03..82dc31c4d6 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt
@@ -19,21 +19,27 @@ package im.vector.app.features.roomdirectory
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
 import im.vector.app.core.extensions.popBackstack
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
+import im.vector.app.features.matrixto.MatrixToBottomSheet
+import im.vector.app.features.navigation.Navigator
 import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs
 import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
 import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerFragment
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import javax.inject.Inject
 
-class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
+@AndroidEntryPoint
+class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>(), MatrixToBottomSheet.InteractionListener {
 
     @Inject lateinit var roomDirectoryViewModelFactory: RoomDirectoryViewModel.Factory
     private val roomDirectoryViewModel: RoomDirectoryViewModel by viewModel()
@@ -43,10 +49,6 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
 
     override fun getCoordinatorLayout() = views.coordinatorLayout
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
@@ -56,8 +58,8 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
         }
 
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         is RoomDirectorySharedAction.Back           -> popBackstack()
                         is RoomDirectorySharedAction.CreateRoom     -> {
@@ -75,7 +77,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
                         is RoomDirectorySharedAction.Close          -> finish()
                     }
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
     }
 
     override fun initUiAndData() {
@@ -84,6 +86,14 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
         }
     }
 
+    override fun mxToBottomSheetNavigateToRoom(roomId: String) {
+        navigator.openRoom(this, roomId)
+    }
+
+    override fun mxToBottomSheetSwitchToSpace(spaceId: String) {
+        navigator.switchToSpace(this, spaceId, Navigator.PostSwitchSpaceAction.None)
+    }
+
     companion object {
         private const val INITIAL_FILTER = "INITIAL_FILTER"
 
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt
index a2089e6cd5..844266e668 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt
@@ -16,16 +16,16 @@
 
 package im.vector.app.features.roomdirectory
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import com.airbnb.mvrx.appendAt
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.settings.VectorPreferences
 import kotlinx.coroutines.CancellationException
@@ -49,18 +49,12 @@ class RoomDirectoryViewModel @AssistedInject constructor(
 ) : VectorViewModel<PublicRoomsViewState, RoomDirectoryAction, RoomDirectoryViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: PublicRoomsViewState): RoomDirectoryViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomDirectoryViewModel, PublicRoomsViewState> {
+        override fun create(initialState: PublicRoomsViewState): RoomDirectoryViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomDirectoryViewModel, PublicRoomsViewState> {
+    companion object : MavericksViewModelFactory<RoomDirectoryViewModel, PublicRoomsViewState> by hiltMavericksViewModelFactory() {
         private const val PUBLIC_ROOMS_LIMIT = 20
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: PublicRoomsViewState): RoomDirectoryViewModel? {
-            val activity: RoomDirectoryActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.roomDirectoryViewModelFactory.create(state)
-        }
     }
 
     private val showAllRooms = vectorPreferences.showAllPublicRooms()
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt
index 4afda8a0e9..b3a21dadb9 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt
@@ -19,19 +19,23 @@ package im.vector.app.features.roomdirectory.createroom
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
 import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
 /**
  * Simple container for [CreateRoomFragment]
  */
+@AndroidEntryPoint
 class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
 
     private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel
@@ -44,10 +48,6 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
         configureToolbar(toolbar)
     }
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         if (isFirstCreation()) {
             addFragment(
@@ -65,14 +65,14 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
         super.onCreate(savedInstanceState)
         sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         is RoomDirectorySharedAction.Back,
                         is RoomDirectorySharedAction.Close -> finish()
                     }
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
     }
 
     companion object {
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt
index ac4c9db89f..1244a0f64e 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt
@@ -23,6 +23,7 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.args
@@ -44,6 +45,8 @@ import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleBottomSheet
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel
 import im.vector.app.features.roomprofile.settings.joinrule.toOption
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
@@ -59,7 +62,6 @@ data class CreateRoomArgs(
 class CreateRoomFragment @Inject constructor(
         private val createRoomController: CreateRoomController,
         private val createSpaceController: CreateSubSpaceController,
-        val createRoomViewModelFactory: CreateRoomViewModel.Factory,
         colorProvider: ColorProvider
 ) : VectorBaseFragment<FragmentCreateRoomBinding>(),
         CreateRoomController.Listener,
@@ -104,11 +106,11 @@ class CreateRoomFragment @Inject constructor(
     private fun setupRoomJoinRuleSharedActionViewModel() {
         roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java)
         roomJoinRuleSharedActionViewModel
-                .observe()
-                .subscribe { action ->
+                .stream()
+                .onEach { action ->
                     viewModel.handle(CreateRoomAction.SetVisibility(action.roomJoinRule))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun showFailure(throwable: Throwable) {
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt
index e0a542dd68..e0ffdc7a52 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt
@@ -17,17 +17,16 @@
 package im.vector.app.features.roomdirectory.createroom
 
 import androidx.core.net.toFile
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.raw.wellknown.getElementWellknown
@@ -60,10 +59,12 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
 ) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: CreateRoomViewState): CreateRoomViewModel
+    interface Factory : MavericksAssistedViewModelFactory<CreateRoomViewModel, CreateRoomViewState> {
+        override fun create(initialState: CreateRoomViewState): CreateRoomViewModel
     }
 
+    companion object : MavericksViewModelFactory<CreateRoomViewModel, CreateRoomViewState> by hiltMavericksViewModelFactory()
+
     init {
         initHomeServerName()
         initAdminE2eByDefault()
@@ -122,16 +123,6 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
         }
     }
 
-    companion object : MavericksViewModelFactory<CreateRoomViewModel, CreateRoomViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: CreateRoomViewState): CreateRoomViewModel? {
-            val fragment: CreateRoomFragment = (viewModelContext as FragmentViewModelContext).fragment()
-
-            return fragment.createRoomViewModelFactory.create(state)
-        }
-    }
-
     override fun handle(action: CreateRoomAction) {
         when (action) {
             is CreateRoomAction.SetAvatar             -> setAvatar(action)
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt
index a32a3a897f..2707b87c1f 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt
@@ -39,8 +39,7 @@ import im.vector.app.features.roomdirectory.RoomDirectoryViewModel
 import timber.log.Timber
 import javax.inject.Inject
 
-class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory,
-                                                      private val roomDirectoryPickerController: RoomDirectoryPickerController
+class RoomDirectoryPickerFragment @Inject constructor(private val roomDirectoryPickerController: RoomDirectoryPickerController
 ) : VectorBaseFragment<FragmentRoomDirectoryPickerBinding>(),
         OnBackPressed,
         RoomDirectoryPickerController.Callback {
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt
index 3f73b80bc6..a5673e78a2 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt
@@ -16,18 +16,17 @@
 
 package im.vector.app.features.roomdirectory.picker
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -46,18 +45,11 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(
 ) : VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomDirectoryPickerViewModel, RoomDirectoryPickerViewState> {
+        override fun create(initialState: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomDirectoryPickerViewModel, RoomDirectoryPickerViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel? {
-            val fragment: RoomDirectoryPickerFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.roomDirectoryPickerViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomDirectoryPickerViewModel, RoomDirectoryPickerViewState> by hiltMavericksViewModelFactory()
 
     init {
         observeAndCompute()
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
index 0121d5d795..86bfdb79cd 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
@@ -20,6 +20,7 @@ import android.content.Context
 import android.content.Intent
 import android.os.Parcelable
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
@@ -51,6 +52,7 @@ data class RoomPreviewData(
         get() = MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl)
 }
 
+@AndroidEntryPoint
 class RoomPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
 
     companion object {
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt
index ef70a31a00..52617e2f1d 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt
@@ -51,7 +51,6 @@ import javax.inject.Inject
  * Note: this Fragment is also used for world readable room for the moment
  */
 class RoomPreviewNoPreviewFragment @Inject constructor(
-        val roomPreviewViewModelFactory: RoomPreviewViewModel.Factory,
         private val avatarRenderer: AvatarRenderer
 ) : VectorBaseFragment<FragmentRoomPreviewNoPreviewBinding>() {
 
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt
index 1df070d3d9..7b012f4fac 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt
@@ -16,15 +16,14 @@
 
 package im.vector.app.features.roomdirectory.roompreview
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -50,18 +49,11 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
     VectorViewModel<RoomPreviewViewState, RoomPreviewAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomPreviewViewState): RoomPreviewViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> {
+        override fun create(initialState: RoomPreviewViewState): RoomPreviewViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomPreviewViewState): RoomPreviewViewModel? {
-            val fragment: RoomPreviewNoPreviewFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.roomPreviewViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomPreviewViewModel, RoomPreviewViewState> by hiltMavericksViewModelFactory()
 
     init {
         // Observe joined room (from the sync)
diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt
index 8c166e7715..c563f6b855 100644
--- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt
@@ -23,21 +23,19 @@ import android.widget.Toast
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.room.RequireActiveMembershipViewEvents
 import im.vector.app.features.room.RequireActiveMembershipViewModel
-import im.vector.app.features.room.RequireActiveMembershipViewState
-import javax.inject.Inject
 
+@AndroidEntryPoint
 class RoomMemberProfileActivity :
         VectorBaseActivity<ActivitySimpleBinding>(),
-        ToolbarConfigurable,
-        RequireActiveMembershipViewModel.Factory {
+        ToolbarConfigurable {
 
     companion object {
         fun newIntent(context: Context, args: RoomMemberProfileArgs): Intent {
@@ -49,17 +47,6 @@ class RoomMemberProfileActivity :
 
     private val requireActiveMembershipViewModel: RequireActiveMembershipViewModel by viewModel()
 
-    @Inject
-    lateinit var requireActiveMembershipViewModelFactory: RequireActiveMembershipViewModel.Factory
-
-    override fun create(initialState: RequireActiveMembershipViewState): RequireActiveMembershipViewModel {
-        return requireActiveMembershipViewModelFactory.create(initialState)
-    }
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(): ActivitySimpleBinding {
         return ActivitySimpleBinding.inflate(layoutInflater)
     }
diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt
index d8e967fd27..48823714f5 100644
--- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt
@@ -66,7 +66,6 @@ data class RoomMemberProfileArgs(
 ) : Parcelable
 
 class RoomMemberProfileFragment @Inject constructor(
-        val viewModelFactory: RoomMemberProfileViewModel.Factory,
         private val roomMemberProfileController: RoomMemberProfileController,
         private val avatarRenderer: AvatarRenderer,
         private val roomDetailPendingActionStore: RoomDetailPendingActionStore
diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt
index e99c8dde64..5b07b101e7 100644
--- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt
@@ -18,16 +18,16 @@
 package im.vector.app.features.roommemberprofile
 
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.mvrx.runCatchingToAsync
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -60,21 +60,14 @@ import org.matrix.android.sdk.flow.unwrap
 class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState,
                                                              private val stringProvider: StringProvider,
                                                              private val session: Session) :
-    VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction, RoomMemberProfileViewEvents>(initialState) {
+        VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction, RoomMemberProfileViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomMemberProfileViewState): RoomMemberProfileViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomMemberProfileViewModel, RoomMemberProfileViewState> {
+        override fun create(initialState: RoomMemberProfileViewState): RoomMemberProfileViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomMemberProfileViewModel, RoomMemberProfileViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomMemberProfileViewState): RoomMemberProfileViewModel? {
-            val fragment: RoomMemberProfileFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomMemberProfileViewModel, RoomMemberProfileViewState> by hiltMavericksViewModelFactory()
 
     private val room = if (initialState.roomId != null) {
         session.getRoom(initialState.roomId)
diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt
index 05ccc57b10..f83ac8f19d 100644
--- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt
@@ -27,17 +27,17 @@ import androidx.fragment.app.Fragment
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetWithFragmentsBinding
 import im.vector.app.features.crypto.verification.VerificationBottomSheet
 import kotlinx.parcelize.Parcelize
-import javax.inject.Inject
 import kotlin.reflect.KClass
 
+@AndroidEntryPoint
 class DeviceListBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetWithFragmentsBinding>() {
 
@@ -47,12 +47,6 @@ class DeviceListBottomSheet :
 
     private val viewModel: DeviceListBottomSheetViewModel by fragmentViewModel(DeviceListBottomSheetViewModel::class)
 
-    @Inject lateinit var viewModelFactory: DeviceListBottomSheetViewModel.Factory
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         viewModel.observeViewEvents {
diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt
index 063f7b6188..d2491237ca 100644
--- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt
@@ -17,7 +17,6 @@
 package im.vector.app.features.roommemberprofile.devices
 
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
@@ -25,7 +24,10 @@ import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import im.vector.app.core.di.HasScreenInjector
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.SingletonEntryPoint
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import org.matrix.android.sdk.api.session.Session
@@ -37,6 +39,8 @@ import org.matrix.android.sdk.flow.flow
 import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
 
 data class DeviceListViewState(
+        val userId: String,
+        val allowDeviceAction: Boolean,
         val userItem: MatrixItem? = null,
         val isMine: Boolean = false,
         val memberCrossSigningKey: MXCrossSigningInfo? = null,
@@ -45,24 +49,41 @@ data class DeviceListViewState(
 ) : MavericksState
 
 class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted private val initialState: DeviceListViewState,
-                                                                 @Assisted private val args: DeviceListBottomSheet.Args,
                                                                  private val session: Session) :
-    VectorViewModel<DeviceListViewState, DeviceListAction, DeviceListBottomSheetViewEvents>(initialState) {
+        VectorViewModel<DeviceListViewState, DeviceListAction, DeviceListBottomSheetViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: DeviceListViewState, args: DeviceListBottomSheet.Args): DeviceListBottomSheetViewModel
+    interface Factory : MavericksAssistedViewModelFactory<DeviceListBottomSheetViewModel, DeviceListViewState> {
+        override fun create(initialState: DeviceListViewState): DeviceListBottomSheetViewModel
+    }
+
+    companion object : MavericksViewModelFactory<DeviceListBottomSheetViewModel, DeviceListViewState> by hiltMavericksViewModelFactory() {
+
+        override fun initialState(viewModelContext: ViewModelContext): DeviceListViewState? {
+            val args = viewModelContext.args<DeviceListBottomSheet.Args>()
+            val userId = args.userId
+            val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
+            return session.getUser(userId)?.toMatrixItem()?.let {
+                DeviceListViewState(
+                        userId = userId,
+                        allowDeviceAction = args.allowDeviceAction,
+                        userItem = it,
+                        isMine = userId == session.myUserId
+                )
+            } ?: return super.initialState(viewModelContext)
+        }
     }
 
     init {
-        session.flow().liveUserCryptoDevices(args.userId)
+
+        session.flow().liveUserCryptoDevices(initialState.userId)
                 .execute {
                     copy(cryptoDevices = it).also {
                         refreshSelectedId()
                     }
                 }
 
-        session.flow().liveCrossSigningInfo(args.userId)
+        session.flow().liveCrossSigningInfo(initialState.userId)
                 .execute {
                     copy(memberCrossSigningKey = it.invoke()?.getOrNull())
                 }
@@ -89,7 +110,7 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva
     }
 
     private fun selectDevice(action: DeviceListAction.SelectDevice) {
-        if (!args.allowDeviceAction) return
+        if (!initialState.allowDeviceAction) return
         setState {
             copy(selectedDevice = action.device)
         }
@@ -102,29 +123,9 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva
     }
 
     private fun manuallyVerify(action: DeviceListAction.ManuallyVerify) {
-        if (!args.allowDeviceAction) return
-        session.cryptoService().verificationService().beginKeyVerification(VerificationMethod.SAS, args.userId, action.deviceId, null)?.let { txID ->
-            _viewEvents.post(DeviceListBottomSheetViewEvents.Verify(args.userId, txID))
-        }
-    }
-
-    companion object : MavericksViewModelFactory<DeviceListBottomSheetViewModel, DeviceListViewState> {
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: DeviceListViewState): DeviceListBottomSheetViewModel? {
-            val fragment: DeviceListBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            val args = viewModelContext.args<DeviceListBottomSheet.Args>()
-            return fragment.viewModelFactory.create(state, args)
-        }
-
-        override fun initialState(viewModelContext: ViewModelContext): DeviceListViewState? {
-            val userId = viewModelContext.args<DeviceListBottomSheet.Args>().userId
-            val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
-            return session.getUser(userId)?.toMatrixItem()?.let {
-                DeviceListViewState(
-                        userItem = it,
-                        isMine = userId == session.myUserId
-                )
-            } ?: return super.initialState(viewModelContext)
+        if (!initialState.allowDeviceAction) return
+        session.cryptoService().verificationService().beginKeyVerification(VerificationMethod.SAS, initialState.userId, action.deviceId, null)?.let { txID ->
+            _viewEvents.post(DeviceListBottomSheetViewEvents.Verify(initialState.userId, txID))
         }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt
index 614c13faa4..5883cb3004 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt
@@ -20,11 +20,12 @@ package im.vector.app.features.roomprofile
 import android.content.Context
 import android.content.Intent
 import android.widget.Toast
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
 import im.vector.app.core.extensions.exhaustive
@@ -34,7 +35,6 @@ import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
 import im.vector.app.features.room.RequireActiveMembershipViewEvents
 import im.vector.app.features.room.RequireActiveMembershipViewModel
-import im.vector.app.features.room.RequireActiveMembershipViewState
 import im.vector.app.features.roomprofile.alias.RoomAliasFragment
 import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
 import im.vector.app.features.roomprofile.members.RoomMemberListFragment
@@ -42,12 +42,14 @@ import im.vector.app.features.roomprofile.notifications.RoomNotificationSettings
 import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
 import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
 import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import javax.inject.Inject
 
+@AndroidEntryPoint
 open class RoomProfileActivity :
         VectorBaseActivity<ActivitySimpleBinding>(),
-        ToolbarConfigurable,
-        RequireActiveMembershipViewModel.Factory {
+        ToolbarConfigurable {
 
     companion object {
 
@@ -71,20 +73,9 @@ open class RoomProfileActivity :
 
     private val requireActiveMembershipViewModel: RequireActiveMembershipViewModel by viewModel()
 
-    @Inject
-    lateinit var requireActiveMembershipViewModelFactory: RequireActiveMembershipViewModel.Factory
-
     @Inject
     lateinit var roomDetailPendingActionStore: RoomDetailPendingActionStore
 
-    override fun create(initialState: RequireActiveMembershipViewState): RequireActiveMembershipViewModel {
-        return requireActiveMembershipViewModelFactory.create(initialState)
-    }
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(): ActivitySimpleBinding {
         return ActivitySimpleBinding.inflate(layoutInflater)
     }
@@ -96,8 +87,8 @@ open class RoomProfileActivity :
             addInitialFragment()
         }
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         RoomProfileSharedAction.OpenRoomMembers                 -> openRoomMembers()
                         RoomProfileSharedAction.OpenRoomSettings                -> openRoomSettings()
@@ -108,7 +99,7 @@ open class RoomProfileActivity :
                         RoomProfileSharedAction.OpenRoomNotificationSettings -> openRoomNotificationSettings()
                     }.exhaustive
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
 
         requireActiveMembershipViewModel.observeViewEvents {
             when (it) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
index e07746af85..e1a5cae907 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt
@@ -26,6 +26,7 @@ import android.view.ViewGroup
 import androidx.core.content.pm.ShortcutManagerCompat
 import androidx.core.view.isVisible
 import androidx.fragment.app.setFragmentResultListener
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
@@ -52,6 +53,8 @@ import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
 import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
 import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
 import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
 import org.matrix.android.sdk.api.util.toMatrixItem
@@ -67,7 +70,6 @@ class RoomProfileFragment @Inject constructor(
         private val roomProfileController: RoomProfileController,
         private val avatarRenderer: AvatarRenderer,
         private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
-        val roomProfileViewModelFactory: RoomProfileViewModel.Factory
 ) :
         VectorBaseFragment<FragmentMatrixProfileBinding>(),
         RoomProfileController.Callback {
@@ -125,9 +127,9 @@ class RoomProfileFragment @Inject constructor(
             }.exhaustive
         }
         roomListQuickActionsSharedActionViewModel
-                .observe()
-                .subscribe { handleQuickActions(it) }
-                .disposeOnDestroyView()
+                .stream()
+                .onEach { handleQuickActions(it) }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
         setupClicks()
         setupLongClicks()
     }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt
index c4fc2bc7bb..472ddfc6b9 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt
@@ -17,13 +17,13 @@
 
 package im.vector.app.features.roomprofile
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -53,18 +53,11 @@ class RoomProfileViewModel @AssistedInject constructor(
 ) : VectorViewModel<RoomProfileViewState, RoomProfileAction, RoomProfileViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomProfileViewState): RoomProfileViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomProfileViewModel, RoomProfileViewState> {
+        override fun create(initialState: RoomProfileViewState): RoomProfileViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomProfileViewModel, RoomProfileViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomProfileViewState): RoomProfileViewModel? {
-            val fragment: RoomProfileFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.roomProfileViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomProfileViewModel, RoomProfileViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt
index 0b144bea9f..15686a6848 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasFragment.kt
@@ -21,6 +21,7 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
@@ -38,13 +39,14 @@ import im.vector.app.features.roomprofile.RoomProfileArgs
 import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheet
 import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetSharedAction
 import im.vector.app.features.roomprofile.alias.detail.RoomAliasBottomSheetSharedActionViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
 class RoomAliasFragment @Inject constructor(
-        val viewModelFactory: RoomAliasViewModel.Factory,
         private val controller: RoomAliasController,
         private val avatarRenderer: AvatarRenderer
 ) :
@@ -78,9 +80,9 @@ class RoomAliasFragment @Inject constructor(
         }
 
         sharedActionViewModel
-                .observe()
-                .subscribe { handleAliasAction(it) }
-                .disposeOnDestroyView()
+                .stream()
+                .onEach { handleAliasAction(it) }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun handleAliasAction(action: RoomAliasBottomSheetSharedAction?) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt
index 68cbfc6170..19f600e5de 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt
@@ -17,15 +17,15 @@
 package im.vector.app.features.roomprofile.alias
 
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
@@ -45,21 +45,14 @@ import org.matrix.android.sdk.flow.unwrap
 
 class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: RoomAliasViewState,
                                                      private val session: Session) :
-    VectorViewModel<RoomAliasViewState, RoomAliasAction, RoomAliasViewEvents>(initialState) {
+        VectorViewModel<RoomAliasViewState, RoomAliasAction, RoomAliasViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomAliasViewState): RoomAliasViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomAliasViewModel, RoomAliasViewState> {
+        override fun create(initialState: RoomAliasViewState): RoomAliasViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomAliasViewModel, RoomAliasViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomAliasViewState): RoomAliasViewModel? {
-            val fragment: RoomAliasFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomAliasViewModel, RoomAliasViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt
index e65efd4936..56dbcbfba4 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheet.kt
@@ -24,7 +24,7 @@ import android.view.ViewGroup
 import androidx.recyclerview.widget.RecyclerView
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -44,23 +44,19 @@ data class RoomAliasBottomSheetArgs(
 /**
  * Bottom sheet fragment that shows room alias information with list of contextual actions
  */
+@AndroidEntryPoint
 class RoomAliasBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
         RoomAliasBottomSheetController.Listener {
 
     private lateinit var sharedActionViewModel: RoomAliasBottomSheetSharedActionViewModel
     @Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
-    @Inject lateinit var roomAliasBottomSheetViewModelFactory: RoomAliasBottomSheetViewModel.Factory
     @Inject lateinit var controller: RoomAliasBottomSheetController
 
     private val viewModel: RoomAliasBottomSheetViewModel by fragmentViewModel(RoomAliasBottomSheetViewModel::class)
 
     override val showExpanded = true
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
         return BottomSheetGenericListBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt
index bc249fc746..0efef6ad8c 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt
@@ -15,12 +15,12 @@
  */
 package im.vector.app.features.roomprofile.alias.detail
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -32,18 +32,11 @@ class RoomAliasBottomSheetViewModel @AssistedInject constructor(
 ) : VectorViewModel<RoomAliasBottomSheetState, EmptyAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomAliasBottomSheetState): RoomAliasBottomSheetViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomAliasBottomSheetViewModel, RoomAliasBottomSheetState> {
+        override fun create(initialState: RoomAliasBottomSheetState): RoomAliasBottomSheetViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomAliasBottomSheetViewModel, RoomAliasBottomSheetState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomAliasBottomSheetState): RoomAliasBottomSheetViewModel? {
-            val fragment: RoomAliasBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.roomAliasBottomSheetViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomAliasBottomSheetViewModel, RoomAliasBottomSheetState> by hiltMavericksViewModelFactory()
 
     init {
         setState {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt
index 72f43639ed..c9fc889242 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListFragment.kt
@@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
 class RoomBannedMemberListFragment @Inject constructor(
-        val viewModelFactory: RoomBannedMemberListViewModel.Factory,
         private val roomMemberListController: RoomBannedMemberListController,
         private val avatarRenderer: AvatarRenderer
 ) : VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt
index e3132c3cc5..d7efc2fb79 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt
@@ -16,13 +16,13 @@
 
 package im.vector.app.features.roomprofile.banned
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -44,11 +44,11 @@ import org.matrix.android.sdk.flow.unwrap
 class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomBannedMemberListViewState,
                                                                 private val stringProvider: StringProvider,
                                                                 private val session: Session) :
-    VectorViewModel<RoomBannedMemberListViewState, RoomBannedMemberListAction, RoomBannedMemberListViewEvents>(initialState) {
+        VectorViewModel<RoomBannedMemberListViewState, RoomBannedMemberListAction, RoomBannedMemberListViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomBannedMemberListViewState): RoomBannedMemberListViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomBannedMemberListViewModel, RoomBannedMemberListViewState> {
+        override fun create(initialState: RoomBannedMemberListViewState): RoomBannedMemberListViewModel
     }
 
     private val room = session.getRoom(initialState.roomId)!!
@@ -77,14 +77,7 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initia
                 }
     }
 
-    companion object : MavericksViewModelFactory<RoomBannedMemberListViewModel, RoomBannedMemberListViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomBannedMemberListViewState): RoomBannedMemberListViewModel? {
-            val fragment: RoomBannedMemberListFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomBannedMemberListViewModel, RoomBannedMemberListViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: RoomBannedMemberListAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt
index ed0b88c8d3..1b58130d85 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt
@@ -29,7 +29,6 @@ import im.vector.app.features.home.AvatarRenderer
 import me.gujun.android.span.span
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.api.session.presence.model.UserPresence
 import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
 import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
 import org.matrix.android.sdk.api.util.MatrixItem
@@ -61,7 +60,7 @@ class RoomMemberListController @Inject constructor(
         roomMemberSummaryFilter.filter = data.filter
 
         val roomMembersByPowerLevel = data.roomMemberSummaries.invoke() ?: return
-        val threePidInvites = data.threePidInvites()
+        val filteredThreePidInvites = data.threePidInvites()
                 ?.filter { event ->
                     event.content.toModel<RoomThirdPartyInviteContent>()
                             ?.takeIf {
@@ -69,7 +68,7 @@ class RoomMemberListController @Inject constructor(
                             } != null
                 }
                 .orEmpty()
-        var threePidInvitesDone = threePidInvites.isEmpty()
+        var threePidInvitesDone = filteredThreePidInvites.isEmpty()
 
         for ((powerLevelCategory, roomMemberList) in roomMembersByPowerLevel) {
             val filteredRoomMemberList = roomMemberList.filter { roomMemberSummaryFilter.test(it) }
@@ -83,7 +82,7 @@ class RoomMemberListController @Inject constructor(
                         stringProvider.getString(RoomMemberListCategories.INVITE.titleRes)
                 )
 
-                buildThreePidInvites(data)
+                buildThreePidInvites(filteredThreePidInvites, data.actionsPermissions.canRevokeThreePidInvite)
                 threePidInvitesDone = true
             }
 
@@ -93,7 +92,7 @@ class RoomMemberListController @Inject constructor(
 
             filteredRoomMemberList.join(
                     each = { _, roomMember ->
-                        buildPresence(roomMember, powerLevelCategory, host, data, roomMember.userPresence)
+                        buildRoomMember(roomMember, powerLevelCategory, host, data)
                     },
                     between = { _, roomMemberBefore ->
                         dividerItem {
@@ -107,7 +106,7 @@ class RoomMemberListController @Inject constructor(
                     id("divider_threepidinvites")
                 }
 
-                buildThreePidInvites(data)
+                buildThreePidInvites(filteredThreePidInvites, data.actionsPermissions.canRevokeThreePidInvite)
                 threePidInvitesDone = true
             }
         }
@@ -118,16 +117,14 @@ class RoomMemberListController @Inject constructor(
                     stringProvider.getString(RoomMemberListCategories.INVITE.titleRes)
             )
 
-            buildThreePidInvites(data)
+            buildThreePidInvites(filteredThreePidInvites, data.actionsPermissions.canRevokeThreePidInvite)
         }
     }
 
-    private fun buildPresence(roomMember: RoomMemberSummary,
-                              powerLevelCategory: RoomMemberListCategories,
-                              host: RoomMemberListController,
-                              data: RoomMemberListViewState,
-                              userPresence: UserPresence?
-    ) {
+    private fun buildRoomMember(roomMember: RoomMemberSummary,
+                                powerLevelCategory: RoomMemberListCategories,
+                                host: RoomMemberListController,
+                                data: RoomMemberListViewState) {
         val powerLabel = stringProvider.getString(powerLevelCategory.titleRes)
 
         profileMatrixItemWithPowerLevelWithPresence {
@@ -138,7 +135,7 @@ class RoomMemberListController @Inject constructor(
             clickListener {
                 host.callback?.onRoomMemberClicked(roomMember)
             }
-            userPresence(userPresence)
+            userPresence(roomMember.userPresence)
             powerLevelLabel(
                     span {
                         span(powerLabel) {
@@ -149,11 +146,10 @@ class RoomMemberListController @Inject constructor(
         }
     }
 
-    private fun buildThreePidInvites(data: RoomMemberListViewState) {
+    private fun buildThreePidInvites(filteredThreePidInvites: List<Event>, canRevokeThreePidInvite: Boolean) {
         val host = this
-        data.threePidInvites()
-                ?.filter { it.content.toModel<RoomThirdPartyInviteContent>() != null }
-                ?.join(
+        filteredThreePidInvites
+                .join(
                         each = { idx, event ->
                             event.content.toModel<RoomThirdPartyInviteContent>()
                                     ?.let { content ->
@@ -161,7 +157,7 @@ class RoomMemberListController @Inject constructor(
                                             id("3pid_$idx")
                                             matrixItem(MatrixItem.UserItem("@", displayName = content.displayName))
                                             avatarRenderer(host.avatarRenderer)
-                                            editable(data.actionsPermissions.canRevokeThreePidInvite)
+                                            editable(canRevokeThreePidInvite)
                                             clickListener {
                                                 host.callback?.onThreePidInviteClicked(event)
                                             }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt
index 4337e8767a..8840f61600 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListFragment.kt
@@ -42,20 +42,14 @@ import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
 class RoomMemberListFragment @Inject constructor(
-        val viewModelFactory: RoomMemberListViewModel.Factory,
         private val roomMemberListController: RoomMemberListController,
         private val avatarRenderer: AvatarRenderer
 ) : VectorBaseFragment<FragmentRoomMemberListBinding>(),
-        RoomMemberListController.Callback,
-        RoomMemberListViewModel.Factory {
+        RoomMemberListController.Callback {
 
     private val viewModel: RoomMemberListViewModel by fragmentViewModel()
     private val roomProfileArgs: RoomProfileArgs by args()
 
-    override fun create(initialState: RoomMemberListViewState): RoomMemberListViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomMemberListBinding {
         return FragmentRoomMemberListBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt
index f16353353c..0bbdd87f3e 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt
@@ -17,22 +17,19 @@
 package im.vector.app.features.roomprofile.members
 
 import androidx.lifecycle.asFlow
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -57,24 +54,14 @@ import timber.log.Timber
 class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomMemberListViewState,
                                                           private val roomMemberSummaryComparator: RoomMemberSummaryComparator,
                                                           private val session: Session) :
-    VectorViewModel<RoomMemberListViewState, RoomMemberListAction, EmptyViewEvents>(initialState) {
+        VectorViewModel<RoomMemberListViewState, RoomMemberListAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomMemberListViewState): RoomMemberListViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomMemberListViewModel, RoomMemberListViewState> {
+        override fun create(initialState: RoomMemberListViewState): RoomMemberListViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomMemberListViewModel, RoomMemberListViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomMemberListViewState): RoomMemberListViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomMemberListViewModel, RoomMemberListViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
@@ -106,7 +93,6 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
 
         if (room.isEncrypted()) {
             room.flow().liveRoomMembers(roomMemberQueryParams)
-                    .flowOn(Dispatchers.Main)
                     .flatMapLatest { membersSummary ->
                         session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId })
                                 .asFlow()
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt
index 449b8663d6..eef8396c1a 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberSummaryFilter.kt
@@ -16,7 +16,7 @@
 
 package im.vector.app.features.roomprofile.members
 
-import io.reactivex.functions.Predicate
+import androidx.core.util.Predicate
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
 import javax.inject.Inject
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt
index f91b482b13..26db6b001e 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt
@@ -16,16 +16,14 @@
 
 package im.vector.app.features.roomprofile.notifications
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
-import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.flow.flow
@@ -37,24 +35,11 @@ class RoomNotificationSettingsViewModel @AssistedInject constructor(
 ) : VectorViewModel<RoomNotificationSettingsViewState, RoomNotificationSettingsAction, RoomNotificationSettingsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomNotificationSettingsViewState): RoomNotificationSettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomNotificationSettingsViewModel, RoomNotificationSettingsViewState> {
+       override fun create(initialState: RoomNotificationSettingsViewState): RoomNotificationSettingsViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomNotificationSettingsViewModel, RoomNotificationSettingsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomNotificationSettingsViewState): RoomNotificationSettingsViewModel {
-            val fragmentModelContext = (viewModelContext as FragmentViewModelContext)
-            return if (fragmentModelContext.fragment is RoomNotificationSettingsFragment) {
-                val fragment: RoomNotificationSettingsFragment = fragmentModelContext.fragment()
-                fragment.viewModelFactory.create(state)
-            } else {
-                val fragment: RoomListQuickActionsBottomSheet = fragmentModelContext.fragment()
-                fragment.roomNotificationSettingsViewModelFactory.create(state)
-            }
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomNotificationSettingsViewModel, RoomNotificationSettingsViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt
index a538c9269b..acf01321c9 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsFragment.kt
@@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
 class RoomPermissionsFragment @Inject constructor(
-        val viewModelFactory: RoomPermissionsViewModel.Factory,
         private val controller: RoomPermissionsController,
         private val avatarRenderer: AvatarRenderer
 ) :
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt
index bf2f2134d6..011c4ea8ae 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt
@@ -16,13 +16,13 @@
 
 package im.vector.app.features.roomprofile.permissions
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
@@ -42,18 +42,11 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat
     VectorViewModel<RoomPermissionsViewState, RoomPermissionsAction, RoomPermissionsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomPermissionsViewState): RoomPermissionsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomPermissionsViewModel, RoomPermissionsViewState> {
+        override fun create(initialState: RoomPermissionsViewState): RoomPermissionsViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomPermissionsViewModel, RoomPermissionsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomPermissionsViewState): RoomPermissionsViewModel? {
-            val fragment: RoomPermissionsFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomPermissionsViewModel, RoomPermissionsViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt
index b7821c056c..0a5f8f4d9a 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt
@@ -24,6 +24,7 @@ import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
@@ -46,13 +47,14 @@ import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistory
 import im.vector.app.features.roomprofile.settings.historyvisibility.RoomHistoryVisibilitySharedActionViewModel
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleActivity
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.model.GuestAccess
 import org.matrix.android.sdk.api.util.toMatrixItem
 import java.util.UUID
 import javax.inject.Inject
 
 class RoomSettingsFragment @Inject constructor(
-        val viewModelFactory: RoomSettingsViewModel.Factory,
         private val controller: RoomSettingsController,
         colorProvider: ColorProvider,
         private val avatarRenderer: AvatarRenderer
@@ -60,8 +62,7 @@ class RoomSettingsFragment @Inject constructor(
         VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
         RoomSettingsController.Callback,
         OnBackPressed,
-        GalleryOrCameraDialogHelper.Listener,
-        RoomSettingsViewModel.Factory {
+        GalleryOrCameraDialogHelper.Listener {
 
     private val viewModel: RoomSettingsViewModel by fragmentViewModel()
     private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
@@ -77,10 +78,6 @@ class RoomSettingsFragment @Inject constructor(
 
     override fun getMenuRes() = R.menu.vector_room_settings
 
-    override fun create(initialState: RoomSettingsViewState): RoomSettingsViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
@@ -107,21 +104,21 @@ class RoomSettingsFragment @Inject constructor(
     private fun setupRoomJoinRuleSharedActionViewModel() {
         roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java)
         roomJoinRuleSharedActionViewModel
-                .observe()
-                .subscribe { action ->
+                .stream()
+                .onEach { action ->
                     viewModel.handle(RoomSettingsAction.SetRoomJoinRule(action.roomJoinRule))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun setupRoomHistoryVisibilitySharedActionViewModel() {
         roomHistoryVisibilitySharedActionViewModel = activityViewModelProvider.get(RoomHistoryVisibilitySharedActionViewModel::class.java)
         roomHistoryVisibilitySharedActionViewModel
-                .observe()
-                .subscribe { action ->
+                .stream()
+                .onEach { action ->
                     viewModel.handle(RoomSettingsAction.SetRoomHistoryVisibility(action.roomHistoryVisibility))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun showSuccess() {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt
index c3c8ca7e2f..1e3cd053b1 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt
@@ -17,13 +17,12 @@
 package im.vector.app.features.roomprofile.settings
 
 import androidx.core.net.toFile
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
@@ -50,24 +49,14 @@ import org.matrix.android.sdk.flow.unwrap
 class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: RoomSettingsViewState,
                                                         private val vectorPreferences: VectorPreferences,
                                                         private val session: Session) :
-    VectorViewModel<RoomSettingsViewState, RoomSettingsAction, RoomSettingsViewEvents>(initialState) {
+        VectorViewModel<RoomSettingsViewState, RoomSettingsAction, RoomSettingsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomSettingsViewState): RoomSettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomSettingsViewModel, RoomSettingsViewState> {
+        override fun create(initialState: RoomSettingsViewState): RoomSettingsViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomSettingsViewModel, RoomSettingsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomSettingsViewState): RoomSettingsViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomSettingsViewModel, RoomSettingsViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
@@ -150,7 +139,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
                             canChangeJoinRule = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true,
                                     EventType.STATE_ROOM_JOIN_RULES) &&
                                     powerLevelsHelper.isUserAllowedToSend(session.myUserId, true,
-                                    EventType.STATE_ROOM_GUEST_ACCESS),
+                                            EventType.STATE_ROOM_GUEST_ACCESS),
                             canAddChildren = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true,
                                     EventType.STATE_SPACE_CHILD)
                     )
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt
index 4089139b78..c63cf918c8 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/historyvisibility/RoomHistoryVisibilityBottomSheet.kt
@@ -21,7 +21,7 @@ import android.os.Parcelable
 import android.view.View
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.ui.bottomsheet.BottomSheetGeneric
 import im.vector.app.core.ui.bottomsheet.BottomSheetGenericController
 import kotlinx.parcelize.Parcelize
@@ -33,16 +33,13 @@ data class RoomHistoryVisibilityBottomSheetArgs(
         val currentRoomHistoryVisibility: RoomHistoryVisibility
 ) : Parcelable
 
+@AndroidEntryPoint
 class RoomHistoryVisibilityBottomSheet : BottomSheetGeneric<RoomHistoryVisibilityState, RoomHistoryVisibilityRadioAction>() {
 
     private lateinit var roomHistoryVisibilitySharedActionViewModel: RoomHistoryVisibilitySharedActionViewModel
     @Inject lateinit var controller: RoomHistoryVisibilityController
     private val viewModel: RoomHistoryVisibilityViewModel by fragmentViewModel(RoomHistoryVisibilityViewModel::class)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getController(): BottomSheetGenericController<RoomHistoryVisibilityState, RoomHistoryVisibilityRadioAction> = controller
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt
index dcce7b2384..c826fe5e64 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt
@@ -27,8 +27,8 @@ import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.commitTransaction
@@ -40,31 +40,23 @@ import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet
 import im.vector.app.features.roomprofile.RoomProfileArgs
 import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedActions
 import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedEvents
+import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedFragment
 import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedState
 import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedViewModel
 import javax.inject.Inject
 
-class RoomJoinRuleActivity : VectorBaseActivity<ActivitySimpleBinding>(),
-        RoomJoinRuleChooseRestrictedViewModel.Factory {
+@AndroidEntryPoint
+class RoomJoinRuleActivity : VectorBaseActivity<ActivitySimpleBinding>() {
 
     override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
 
     private lateinit var roomProfileArgs: RoomProfileArgs
 
-    @Inject
-    lateinit var allowListViewModelFactory: RoomJoinRuleChooseRestrictedViewModel.Factory
-
     @Inject
     lateinit var errorFormatter: ErrorFormatter
 
     val viewModel: RoomJoinRuleChooseRestrictedViewModel by viewModel()
 
-    override fun create(initialState: RoomJoinRuleChooseRestrictedState) = allowListViewModelFactory.create(initialState)
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         roomProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return
         if (isFirstCreation()) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt
index f0f8193cc5..4185c2031b 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleBottomSheet.kt
@@ -21,7 +21,7 @@ import android.os.Parcelable
 import android.view.View
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.ui.bottomsheet.BottomSheetGeneric
 import im.vector.app.core.ui.bottomsheet.BottomSheetGenericController
 import kotlinx.parcelize.Parcelize
@@ -44,16 +44,13 @@ data class RoomJoinRuleBottomSheetArgs(
         val parentSpaceName: String?
 ) : Parcelable
 
+@AndroidEntryPoint
 class RoomJoinRuleBottomSheet : BottomSheetGeneric<RoomJoinRuleState, RoomJoinRuleRadioAction>() {
 
     private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
     @Inject lateinit var controller: RoomJoinRuleController
     private val viewModel: RoomJoinRuleViewModel by fragmentViewModel(RoomJoinRuleViewModel::class)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getController(): BottomSheetGenericController<RoomJoinRuleState, RoomJoinRuleRadioAction> = controller
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedFragment.kt
index 6d5d9c1f30..b65e90aeed 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedFragment.kt
@@ -14,27 +14,26 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.roomprofile.settings.joinrule
+package im.vector.app.features.roomprofile.settings.joinrule.advanced
 
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.appcompat.queryTextChanges
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.OnBackPressed
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentSpaceRestrictedSelectBinding
 import im.vector.app.features.home.AvatarRenderer
-import im.vector.app.features.roomprofile.settings.joinrule.advanced.ChooseRestrictedController
-import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedActions
-import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRuleChooseRestrictedViewModel
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.util.MatrixItem
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.appcompat.queryTextChanges
 import javax.inject.Inject
 
 class RoomJoinRuleChooseRestrictedFragment @Inject constructor(
@@ -54,11 +53,11 @@ class RoomJoinRuleChooseRestrictedFragment @Inject constructor(
         controller.listener = this
         views.recyclerView.configureWith(controller)
         views.roomsFilter.queryTextChanges()
-                .debounce(500, TimeUnit.MILLISECONDS)
-                .subscribeBy {
+                .debounce(500)
+                .onEach {
                     viewModel.handle(RoomJoinRuleChooseRestrictedActions.FilterWith(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.okButton.debouncedClicks {
             parentFragmentManager.popBackStack()
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt
index 1e7f1d2111..4bd7568ccd 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt
@@ -18,19 +18,17 @@ package im.vector.app.features.roomprofile.settings.joinrule.advanced
 
 import android.graphics.Typeface
 import androidx.core.text.toSpannable
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -175,8 +173,8 @@ class RoomJoinRuleChooseRestrictedViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomJoinRuleChooseRestrictedState): RoomJoinRuleChooseRestrictedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomJoinRuleChooseRestrictedViewModel, RoomJoinRuleChooseRestrictedState> {
+        override fun create(initialState: RoomJoinRuleChooseRestrictedState): RoomJoinRuleChooseRestrictedViewModel
     }
 
     override fun handle(action: RoomJoinRuleChooseRestrictedActions) {
@@ -391,14 +389,5 @@ class RoomJoinRuleChooseRestrictedViewModel @AssistedInject constructor(
         }
     }
 
-    companion object : MavericksViewModelFactory<RoomJoinRuleChooseRestrictedViewModel, RoomJoinRuleChooseRestrictedState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: RoomJoinRuleChooseRestrictedState): RoomJoinRuleChooseRestrictedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomJoinRuleChooseRestrictedViewModel, RoomJoinRuleChooseRestrictedState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt
index f079daf262..3716d9682c 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt
@@ -42,11 +42,9 @@ import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
 class RoomUploadsFragment @Inject constructor(
-        private val viewModelFactory: RoomUploadsViewModel.Factory,
         private val avatarRenderer: AvatarRenderer,
         private val notificationUtils: NotificationUtils
-) : VectorBaseFragment<FragmentRoomUploadsBinding>(),
-        RoomUploadsViewModel.Factory by viewModelFactory {
+) : VectorBaseFragment<FragmentRoomUploadsBinding>() {
 
     private val roomProfileArgs: RoomProfileArgs by args()
 
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt
index 3d3ad375ea..92ff33395e 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt
@@ -16,16 +16,15 @@
 
 package im.vector.app.features.roomprofile.uploads
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.launch
@@ -40,21 +39,11 @@ class RoomUploadsViewModel @AssistedInject constructor(
 ) : VectorViewModel<RoomUploadsViewState, RoomUploadsAction, RoomUploadsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomUploadsViewState): RoomUploadsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomUploadsViewModel, RoomUploadsViewState> {
+        override fun create(initialState: RoomUploadsViewState): RoomUploadsViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomUploadsViewModel, RoomUploadsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomUploadsViewState): RoomUploadsViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomUploadsViewModel, RoomUploadsViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)!!
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt b/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt
index 5afcb77587..e21366db02 100644
--- a/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt
@@ -26,7 +26,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NA
 import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
 import org.matrix.android.sdk.flow.flow
-import org.matrix.android.sdk.rx.SecretsSynchronisationInfo
 
 data class SecretsSynchronisationInfo(
         val isBackupSetup: Boolean,
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt
index 7cd4fc2d3d..399379ed97 100755
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt
@@ -20,13 +20,12 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.os.Parcelable
-import android.util.Log
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
 import androidx.preference.Preference
 import androidx.preference.PreferenceFragmentCompat
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityVectorSettingsBinding
@@ -45,6 +44,7 @@ private const val KEY_ACTIVITY_PAYLOAD = "settings-activity-payload"
 /**
  * Displays the client settings.
  */
+@AndroidEntryPoint
 class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>(),
         PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
         FragmentManager.OnBackStackChangedListener,
@@ -62,10 +62,6 @@ class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>
 
     @Inject lateinit var session: Session
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         configureToolbar(views.settingsToolbar)
 
@@ -89,7 +85,6 @@ class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>
                     replaceFragment(R.id.vector_settings_page, VectorSettingsNotificationPreferenceFragment::class.java, null, FRAGMENT_TAG)
                 }
                 is SettingsActivityPayload.DiscoverySettings          -> {
-                    Log.e("!!!", "SettingsActivityPayload.DiscoverySettings : $payload")
                     replaceFragment(R.id.vector_settings_page, DiscoverySettingsFragment::class.java, payload, FRAGMENT_TAG)
                 }
                 else                                                  ->
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt
index eb72b1e9a4..39fc292c2b 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt
@@ -23,18 +23,14 @@ import androidx.annotation.CallSuper
 import de.spiritcroc.preference.ScPreferenceFragment
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import im.vector.app.R
-import im.vector.app.core.di.DaggerScreenComponent
-import im.vector.app.core.di.HasScreenInjector
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.core.utils.toast
-import io.reactivex.disposables.CompositeDisposable
-import io.reactivex.disposables.Disposable
 import org.matrix.android.sdk.api.session.Session
 import timber.log.Timber
 
-abstract class VectorSettingsBaseFragment : ScPreferenceFragment(), HasScreenInjector {
+abstract class VectorSettingsBaseFragment : ScPreferenceFragment() {
 
     val vectorActivity: VectorBaseActivity<*> by lazy {
         activity as VectorBaseActivity<*>
@@ -45,7 +41,6 @@ abstract class VectorSettingsBaseFragment : ScPreferenceFragment(), HasScreenInj
     // members
     protected lateinit var session: Session
     protected lateinit var errorFormatter: ErrorFormatter
-    private lateinit var screenComponent: ScreenComponent
 
     abstract val preferenceXmlRes: Int
 
@@ -56,17 +51,10 @@ abstract class VectorSettingsBaseFragment : ScPreferenceFragment(), HasScreenInj
     }
 
     override fun onAttach(context: Context) {
-        screenComponent = DaggerScreenComponent.factory().create(vectorActivity.getVectorComponent(), vectorActivity)
+        val singletonEntryPoint = context.singletonEntryPoint()
         super.onAttach(context)
-        session = screenComponent.activeSessionHolder().getActiveSession()
-        errorFormatter = screenComponent.errorFormatter()
-        injectWith(injector())
-    }
-
-    protected open fun injectWith(injector: ScreenComponent) = Unit
-
-    override fun injector(): ScreenComponent {
-        return screenComponent
+        session = singletonEntryPoint.activeSessionHolder().getActiveSession()
+        errorFormatter = singletonEntryPoint.errorFormatter()
     }
 
     override fun onResume() {
@@ -77,31 +65,10 @@ abstract class VectorSettingsBaseFragment : ScPreferenceFragment(), HasScreenInj
         mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views)
     }
 
-    @CallSuper
-    override fun onDestroyView() {
-        uiDisposables.clear()
-        super.onDestroyView()
-    }
-
-    override fun onDestroy() {
-        uiDisposables.dispose()
-        super.onDestroy()
-    }
-
     abstract fun bindPref()
 
     abstract var titleRes: Int
 
-    /* ==========================================================================================
-     * Disposable
-     * ========================================================================================== */
-
-    private val uiDisposables = CompositeDisposable()
-
-    protected fun Disposable.disposeOnDestroyView() {
-        uiDisposables.add(this)
-    }
-
     /* ==========================================================================================
      * Protected
      * ========================================================================================== */
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt
index 1a04dab950..254c82e285 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt
@@ -55,7 +55,7 @@ class VectorSettingsPinFragment @Inject constructor(
 
         useCompleteNotificationPref.setOnPreferenceChangeListener { _, _ ->
             // Refresh the drawer for an immediate effect of this change
-            notificationDrawerManager.refreshNotificationDrawer()
+            notificationDrawerManager.notificationStyleChanged()
             true
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
index 7e60e69379..438382ab3c 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
@@ -58,19 +58,16 @@ import im.vector.app.features.pin.PinMode
 import im.vector.app.features.raw.wellknown.getElementWellknown
 import im.vector.app.features.raw.wellknown.isE2EByDefault
 import im.vector.app.features.themes.ThemeUtils
-import io.reactivex.disposables.Disposable
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 import me.gujun.android.span.span
 import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
+import org.matrix.android.sdk.api.raw.RawService
 import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
 import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
 import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse
-import org.matrix.android.sdk.rx.SecretsSynchronisationInfo
 import javax.inject.Inject
 
 class VectorSettingsSecurityPrivacyFragment @Inject constructor(
@@ -79,12 +76,12 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
         private val pinCodeStore: PinCodeStore,
         private val keysExporter: KeysExporter,
         private val keysImporter: KeysImporter,
+        private val rawService: RawService,
         private val navigator: Navigator
 ) : VectorSettingsBaseFragment() {
 
     override var titleRes = R.string.settings_security_and_privacy
     override val preferenceXmlRes = R.xml.vector_settings_security_privacy
-    private var disposables = mutableListOf<Disposable>()
 
     // cryptography
     private val mCryptographyCategory by lazy {
@@ -147,16 +144,15 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
         refreshMyDevice()
         refreshXSigningStatus()
         session.liveSecretSynchronisationInfo()
-                .flowOn(Dispatchers.Main)
                 .onEach {
                     refresh4SSection(it)
                     refreshXSigningStatus()
-                }.launchIn(viewLifecycleOwner.lifecycleScope)
+                }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         lifecycleScope.launchWhenResumed {
             findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible =
-                    vectorActivity.getVectorComponent()
-                            .rawService()
+                    rawService
                             .getElementWellknown(session.sessionParams)
                             ?.isE2EByDefault() == false
         }
@@ -172,14 +168,6 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
 //        findPreference<VectorPreference>(VectorPreferences.SETTINGS_SECURE_BACKUP_RESET_PREFERENCE_KEY)
 //    }
 
-    override fun onPause() {
-        super.onPause()
-        disposables.forEach {
-            it.dispose()
-        }
-        disposables.clear()
-    }
-
     private fun refresh4SSection(info: SecretsSynchronisationInfo) {
         // it's a lot of if / else if / else
         // But it's not yet clear how to manage all cases
diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt
index 4e599e81fb..5729e773b7 100644
--- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt
@@ -36,9 +36,7 @@ import im.vector.app.features.settings.VectorSettingsActivity
 import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
 import javax.inject.Inject
 
-class DeactivateAccountFragment @Inject constructor(
-        val viewModelFactory: DeactivateAccountViewModel.Factory
-) : VectorBaseFragment<FragmentDeactivateAccountBinding>() {
+class DeactivateAccountFragment @Inject constructor() : VectorBaseFragment<FragmentDeactivateAccountBinding>() {
 
     private val viewModel: DeactivateAccountViewModel by fragmentViewModel()
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt
index 5aaa0be13a..922435047f 100644
--- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt
@@ -15,14 +15,13 @@
  */
 package im.vector.app.features.settings.account.deactivation
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.auth.ReAuthActivity
@@ -49,8 +48,8 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
     VectorViewModel<DeactivateAccountViewState, DeactivateAccountAction, DeactivateAccountViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: DeactivateAccountViewState): DeactivateAccountViewModel
+    interface Factory : MavericksAssistedViewModelFactory<DeactivateAccountViewModel, DeactivateAccountViewState> {
+        override fun create(initialState: DeactivateAccountViewState): DeactivateAccountViewModel
     }
 
     var uiaContinuation: Continuation<UIABaseAuth>? = null
@@ -114,12 +113,5 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
         }
     }
 
-    companion object : MavericksViewModelFactory<DeactivateAccountViewModel, DeactivateAccountViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: DeactivateAccountViewState): DeactivateAccountViewModel? {
-            val fragment: DeactivateAccountFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<DeactivateAccountViewModel, DeactivateAccountViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt
index d60d9138d7..fa061cdf8d 100644
--- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsFragment.kt
@@ -42,7 +42,6 @@ import javax.inject.Inject
  */
 class CrossSigningSettingsFragment @Inject constructor(
         private val controller: CrossSigningSettingsController,
-        val viewModelFactory: CrossSigningSettingsViewModel.Factory
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
         CrossSigningSettingsController.InteractionListener {
 
@@ -55,14 +54,14 @@ class CrossSigningSettingsFragment @Inject constructor(
     private val reAuthActivityResultLauncher = registerStartForActivityResult { activityResult ->
         if (activityResult.resultCode == Activity.RESULT_OK) {
             when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) {
-                LoginFlowTypes.SSO -> {
+                LoginFlowTypes.SSO      -> {
                     viewModel.handle(CrossSigningSettingsAction.SsoAuthDone)
                 }
                 LoginFlowTypes.PASSWORD -> {
                     val password = activityResult.data?.extras?.getString(ReAuthActivity.RESULT_VALUE) ?: ""
                     viewModel.handle(CrossSigningSettingsAction.PasswordAuthDone(password))
                 }
-                else -> {
+                else                    -> {
                     viewModel.handle(CrossSigningSettingsAction.ReAuthCancelled)
                 }
             }
@@ -78,7 +77,7 @@ class CrossSigningSettingsFragment @Inject constructor(
         setupRecyclerView()
         viewModel.observeViewEvents { event ->
             when (event) {
-                is CrossSigningSettingsViewEvents.Failure -> {
+                is CrossSigningSettingsViewEvents.Failure              -> {
                     MaterialAlertDialogBuilder(requireContext())
                             .setTitle(R.string.dialog_title_error)
                             .setMessage(errorFormatter.toHumanReadable(event.throwable))
@@ -86,7 +85,7 @@ class CrossSigningSettingsFragment @Inject constructor(
                             .show()
                     Unit
                 }
-                is CrossSigningSettingsViewEvents.RequestReAuth -> {
+                is CrossSigningSettingsViewEvents.RequestReAuth        -> {
                     ReAuthActivity.newIntent(requireContext(),
                             event.registrationFlowResponse,
                             event.lastErrorCode,
@@ -98,7 +97,7 @@ class CrossSigningSettingsFragment @Inject constructor(
                     views.waitingView.waitingView.isVisible = true
                     views.waitingView.waitingStatusText.setTextOrHide(event.status)
                 }
-                CrossSigningSettingsViewEvents.HideModalWaitingView -> {
+                CrossSigningSettingsViewEvents.HideModalWaitingView    -> {
                     views.waitingView.waitingView.isVisible = false
                 }
             }.exhaustive
diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
index 033d9cf716..644b7f33dd 100644
--- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
@@ -15,13 +15,13 @@
  */
 package im.vector.app.features.settings.crosssigning
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -61,27 +61,27 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
         ) { myDevicesInfo, mxCrossSigningInfo ->
             myDevicesInfo to mxCrossSigningInfo
         }
-        .execute { data ->
-            val crossSigningKeys = data.invoke()?.second?.getOrNull()
-            val xSigningIsEnableInAccount = crossSigningKeys != null
-            val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified()
-            val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign()
+                .execute { data ->
+                    val crossSigningKeys = data.invoke()?.second?.getOrNull()
+                    val xSigningIsEnableInAccount = crossSigningKeys != null
+                    val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified()
+                    val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign()
 
-            copy(
-                    crossSigningInfo = crossSigningKeys,
-                    xSigningIsEnableInAccount = xSigningIsEnableInAccount,
-                    xSigningKeysAreTrusted = xSigningKeysAreTrusted,
-                    xSigningKeyCanSign = xSigningKeyCanSign
-            )
-        }
+                    copy(
+                            crossSigningInfo = crossSigningKeys,
+                            xSigningIsEnableInAccount = xSigningIsEnableInAccount,
+                            xSigningKeysAreTrusted = xSigningKeysAreTrusted,
+                            xSigningKeyCanSign = xSigningKeyCanSign
+                    )
+                }
     }
 
     var uiaContinuation: Continuation<UIABaseAuth>? = null
     var pendingAuth: UIABaseAuth? = null
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: CrossSigningSettingsViewState): CrossSigningSettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<CrossSigningSettingsViewModel, CrossSigningSettingsViewState> {
+        override fun create(initialState: CrossSigningSettingsViewState): CrossSigningSettingsViewModel
     }
 
     override fun handle(action: CrossSigningSettingsAction) {
@@ -154,12 +154,5 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
         _viewEvents.post(CrossSigningSettingsViewEvents.Failure(Exception(stringProvider.getString(R.string.failed_to_initialize_cross_signing))))
     }
 
-    companion object : MavericksViewModelFactory<CrossSigningSettingsViewModel, CrossSigningSettingsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: CrossSigningSettingsViewState): CrossSigningSettingsViewModel? {
-            val fragment: CrossSigningSettingsFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<CrossSigningSettingsViewModel, CrossSigningSettingsViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt
index 7ba6042027..441a344660 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt
@@ -25,7 +25,7 @@ import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.parentFragmentViewModel
 import com.airbnb.mvrx.withState
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
@@ -39,6 +39,7 @@ data class DeviceVerificationInfoArgs(
         val deviceId: String
 ) : Parcelable
 
+@AndroidEntryPoint
 class DeviceVerificationInfoBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
         DeviceVerificationInfoBottomSheetController.Callback {
@@ -47,12 +48,6 @@ class DeviceVerificationInfoBottomSheet :
 
     private val sharedViewModel: DevicesViewModel by parentFragmentViewModel(DevicesViewModel::class)
 
-    @Inject lateinit var deviceVerificationInfoViewModelFactory: DeviceVerificationInfoBottomSheetViewModel.Factory
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     @Inject lateinit var controller: DeviceVerificationInfoBottomSheetController
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt
index e6cde74440..3a944b5a71 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt
@@ -15,13 +15,13 @@
  */
 package im.vector.app.features.settings.devices
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -31,15 +31,17 @@ import org.matrix.android.sdk.flow.flow
 import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
 
 class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: DeviceVerificationInfoBottomSheetViewState,
-                                                                             @Assisted val deviceId: String,
                                                                              val session: Session
 ) : VectorViewModel<DeviceVerificationInfoBottomSheetViewState, EmptyAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: DeviceVerificationInfoBottomSheetViewState, deviceId: String): DeviceVerificationInfoBottomSheetViewModel
+    interface Factory : MavericksAssistedViewModelFactory<DeviceVerificationInfoBottomSheetViewModel, DeviceVerificationInfoBottomSheetViewState> {
+        override fun create(initialState: DeviceVerificationInfoBottomSheetViewState): DeviceVerificationInfoBottomSheetViewModel
     }
 
+    companion object : MavericksViewModelFactory<DeviceVerificationInfoBottomSheetViewModel, DeviceVerificationInfoBottomSheetViewState>
+    by hiltMavericksViewModelFactory()
+
     init {
 
         setState {
@@ -59,7 +61,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
 
         session.flow().liveUserCryptoDevices(session.myUserId)
                 .map { list ->
-                    list.firstOrNull { it.deviceId == deviceId }
+                    list.firstOrNull { it.deviceId == initialState.deviceId }
                 }
                 .execute {
                     copy(
@@ -82,24 +84,13 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As
 
         session.flow().liveMyDevicesInfo()
                 .map { devices ->
-                    devices.firstOrNull { it.deviceId == deviceId } ?: DeviceInfo(deviceId = deviceId)
+                    devices.firstOrNull { it.deviceId == initialState.deviceId } ?: DeviceInfo(deviceId = initialState.deviceId)
                 }
                 .execute {
                     copy(deviceInfo = it)
                 }
     }
 
-    companion object : MavericksViewModelFactory<DeviceVerificationInfoBottomSheetViewModel, DeviceVerificationInfoBottomSheetViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: DeviceVerificationInfoBottomSheetViewState):
-                DeviceVerificationInfoBottomSheetViewModel? {
-            val fragment: DeviceVerificationInfoBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            val args = viewModelContext.args<DeviceVerificationInfoArgs>()
-            return fragment.deviceVerificationInfoViewModelFactory.create(state, args.deviceId)
-        }
-    }
-
     override fun handle(action: EmptyAction) {
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt
index e320642ed0..32927ca068 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt
@@ -23,6 +23,7 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
 
 data class DeviceVerificationInfoBottomSheetViewState(
+        val deviceId: String,
         val cryptoDeviceInfo: Async<CryptoDeviceInfo?> = Uninitialized,
         val deviceInfo: Async<DeviceInfo> = Uninitialized,
         val hasAccountCrossSigning: Boolean = false,
@@ -32,6 +33,7 @@ data class DeviceVerificationInfoBottomSheetViewState(
         val isRecoverySetup: Boolean = false
 ) : MavericksState {
 
-    val canVerifySession: Boolean
-        get() = hasOtherSessions || isRecoverySetup
+    constructor(args: DeviceVerificationInfoArgs) : this(deviceId = args.deviceId)
+
+    val canVerifySession = hasOtherSessions || isRecoverySetup
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt
index a8154c3e11..67ed2e18f2 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt
@@ -18,22 +18,23 @@ package im.vector.app.features.settings.devices
 
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.utils.PublishDataSource
 import im.vector.app.features.auth.ReAuthActivity
 import im.vector.app.features.login.ReAuthHelper
-import io.reactivex.subjects.PublishSubject
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -64,7 +65,6 @@ import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth
 import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
 import org.matrix.android.sdk.internal.util.awaitCallback
 import timber.log.Timber
-import java.util.concurrent.TimeUnit
 import javax.net.ssl.HttpsURLConnection
 import kotlin.coroutines.Continuation
 import kotlin.coroutines.resume
@@ -97,20 +97,13 @@ class DevicesViewModel @AssistedInject constructor(
     var pendingAuth: UIABaseAuth? = null
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: DevicesViewState): DevicesViewModel
+    interface Factory : MavericksAssistedViewModelFactory<DevicesViewModel, DevicesViewState> {
+        override fun create(initialState: DevicesViewState): DevicesViewModel
     }
 
-    companion object : MavericksViewModelFactory<DevicesViewModel, DevicesViewState> {
+    companion object : MavericksViewModelFactory<DevicesViewModel, DevicesViewState> by hiltMavericksViewModelFactory()
 
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: DevicesViewState): DevicesViewModel? {
-            val fragment: VectorSettingsDevicesFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.devicesViewModelFactory.create(state)
-        }
-    }
-
-    private val refreshPublisher: PublishSubject<Unit> = PublishSubject.create()
+    private val refreshSource = PublishDataSource<Unit>()
 
     init {
 
@@ -173,12 +166,12 @@ class DevicesViewModel @AssistedInject constructor(
 //                    )
 //                }
 
-        refreshPublisher.throttleFirst(4_000, TimeUnit.MILLISECONDS)
-                .subscribe {
+        refreshSource.stream().throttleFirst(4_000)
+                .onEach {
                     session.cryptoService().fetchDevicesList(NoOpMatrixCallback())
                     session.cryptoService().downloadKeys(listOf(session.myUserId), true, NoOpMatrixCallback())
                 }
-                .disposeOnClear()
+                .launchIn(viewModelScope)
         // then force download
         queryRefreshDevicesList()
     }
@@ -200,7 +193,7 @@ class DevicesViewModel @AssistedInject constructor(
      * It can be any mobile devices, and any browsers.
      */
     private fun queryRefreshDevicesList() {
-        refreshPublisher.onNext(Unit)
+        refreshSource.post(Unit)
     }
 
     override fun handle(action: DevicesAction) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt
index 62923d4f3d..531e9a944b 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt
@@ -47,7 +47,6 @@ import javax.inject.Inject
  * Display the list of the user's device
  */
 class VectorSettingsDevicesFragment @Inject constructor(
-        val devicesViewModelFactory: DevicesViewModel.Factory,
         private val devicesController: DevicesController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
         DevicesController.Callback {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt
index 570da6875a..a586e14d99 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataFragment.kt
@@ -37,7 +37,6 @@ import org.matrix.android.sdk.internal.di.MoshiProvider
 import javax.inject.Inject
 
 class AccountDataFragment @Inject constructor(
-        val viewModelFactory: AccountDataViewModel.Factory,
         private val epoxyController: AccountDataEpoxyController,
         private val colorProvider: ColorProvider
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt
index 104ee71edc..6289699687 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt
@@ -17,14 +17,14 @@
 package im.vector.app.features.settings.devtools
 
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -61,16 +61,9 @@ class AccountDataViewModel @AssistedInject constructor(@Assisted initialState: A
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: AccountDataViewState): AccountDataViewModel
+    interface Factory : MavericksAssistedViewModelFactory<AccountDataViewModel, AccountDataViewState> {
+        override fun create(initialState: AccountDataViewState): AccountDataViewModel
     }
 
-    companion object : MavericksViewModelFactory<AccountDataViewModel, AccountDataViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: AccountDataViewState): AccountDataViewModel? {
-            val fragment: AccountDataFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<AccountDataViewModel, AccountDataViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt
index 7325288c55..83740c5018 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailFragment.kt
@@ -34,7 +34,6 @@ import org.matrix.android.sdk.api.session.events.model.Event
 import javax.inject.Inject
 
 class GossipingEventsPaperTrailFragment @Inject constructor(
-        val viewModelFactory: GossipingEventsPaperTrailViewModel.Factory,
         private val epoxyController: GossipingTrailPagedEpoxyController,
         private val colorProvider: ColorProvider
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt
index fd09b38919..dde032d303 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt
@@ -19,15 +19,15 @@ package im.vector.app.features.settings.devtools
 import androidx.lifecycle.asFlow
 import androidx.paging.PagedList
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -60,17 +60,9 @@ class GossipingEventsPaperTrailViewModel @AssistedInject constructor(@Assisted i
     override fun handle(action: EmptyAction) {}
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: GossipingEventsPaperTrailState): GossipingEventsPaperTrailViewModel
+    interface Factory : MavericksAssistedViewModelFactory<GossipingEventsPaperTrailViewModel, GossipingEventsPaperTrailState> {
+        override fun create(initialState: GossipingEventsPaperTrailState): GossipingEventsPaperTrailViewModel
     }
 
-    companion object : MavericksViewModelFactory<GossipingEventsPaperTrailViewModel, GossipingEventsPaperTrailState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: GossipingEventsPaperTrailState): GossipingEventsPaperTrailViewModel? {
-            val fragment: GossipingEventsPaperTrailFragment = (viewModelContext as FragmentViewModelContext).fragment()
-
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<GossipingEventsPaperTrailViewModel, GossipingEventsPaperTrailState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt
index 8bf89d975c..ac4bef9c94 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/IncomingKeyRequestListFragment.kt
@@ -30,7 +30,6 @@ import im.vector.app.databinding.FragmentGenericRecyclerBinding
 import javax.inject.Inject
 
 class IncomingKeyRequestListFragment @Inject constructor(
-        val viewModelFactory: KeyRequestListViewModel.Factory,
         private val epoxyController: IncomingKeyRequestPagedController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>() {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt
index 37decc4a12..197a72cb05 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt
@@ -17,17 +17,16 @@
 package im.vector.app.features.settings.devtools
 
 import androidx.lifecycle.asFlow
-import androidx.lifecycle.viewModelScope
 import androidx.paging.PagedList
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -43,7 +42,7 @@ data class KeyRequestListViewState(
 
 class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState: KeyRequestListViewState,
                                                           private val session: Session) :
-    VectorViewModel<KeyRequestListViewState, EmptyAction, EmptyViewEvents>(initialState) {
+        VectorViewModel<KeyRequestListViewState, EmptyAction, EmptyViewEvents>(initialState) {
 
     init {
         refresh()
@@ -67,19 +66,9 @@ class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState
     override fun handle(action: EmptyAction) {}
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: KeyRequestListViewState): KeyRequestListViewModel
+    interface Factory : MavericksAssistedViewModelFactory<KeyRequestListViewModel, KeyRequestListViewState> {
+        override fun create(initialState: KeyRequestListViewState): KeyRequestListViewModel
     }
 
-    companion object : MavericksViewModelFactory<KeyRequestListViewModel, KeyRequestListViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: KeyRequestListViewState): KeyRequestListViewModel? {
-            val context = viewModelContext as FragmentViewModelContext
-            val factory = (context.fragment as? IncomingKeyRequestListFragment)?.viewModelFactory
-                    ?: (context.fragment as? OutgoingKeyRequestListFragment)?.viewModelFactory
-
-            return factory?.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<KeyRequestListViewModel, KeyRequestListViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt
index 362502d7d8..f480eb2db8 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt
@@ -17,19 +17,18 @@
 package im.vector.app.features.settings.devtools
 
 import android.net.Uri
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -56,18 +55,11 @@ class KeyRequestViewModel @AssistedInject constructor(
     VectorViewModel<KeyRequestViewState, KeyRequestAction, KeyRequestEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: KeyRequestViewState): KeyRequestViewModel
+    interface Factory : MavericksAssistedViewModelFactory<KeyRequestViewModel, KeyRequestViewState> {
+        override fun create(initialState: KeyRequestViewState): KeyRequestViewModel
     }
 
-    companion object : MavericksViewModelFactory<KeyRequestViewModel, KeyRequestViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: KeyRequestViewState): KeyRequestViewModel? {
-            val fragment: KeyRequestsFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<KeyRequestViewModel, KeyRequestViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: KeyRequestAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt
index 0b3d8812f1..d807fc620a 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt
@@ -41,8 +41,7 @@ import im.vector.app.databinding.FragmentDevtoolKeyrequestsBinding
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import javax.inject.Inject
 
-class KeyRequestsFragment @Inject constructor(
-        val viewModelFactory: KeyRequestViewModel.Factory) : VectorBaseFragment<FragmentDevtoolKeyrequestsBinding>() {
+class KeyRequestsFragment @Inject constructor() : VectorBaseFragment<FragmentDevtoolKeyrequestsBinding>() {
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDevtoolKeyrequestsBinding {
         return FragmentDevtoolKeyrequestsBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt
index 0cbca2f38a..0483d5fb4d 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devtools/OutgoingKeyRequestListFragment.kt
@@ -29,7 +29,6 @@ import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentGenericRecyclerBinding
 import javax.inject.Inject
 class OutgoingKeyRequestListFragment @Inject constructor(
-        val viewModelFactory: KeyRequestListViewModel.Factory,
         private val epoxyController: OutgoingKeyRequestPagedController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>() {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsFragment.kt
index 20541a1ebb..28bce90424 100644
--- a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsFragment.kt
@@ -34,7 +34,6 @@ import javax.inject.Inject
  * Display some information about the homeserver
  */
 class HomeserverSettingsFragment @Inject constructor(
-        val homeserverSettingsViewModelFactory: HomeserverSettingsViewModel.Factory,
         private val homeserverSettingsController: HomeserverSettingsController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
         HomeserverSettingsController.Callback {
diff --git a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt
index 91ad34f1b6..fab563b49e 100644
--- a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt
@@ -16,16 +16,15 @@
 
 package im.vector.app.features.settings.homeserver
 
-import androidx.lifecycle.viewModelScope
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.launch
@@ -37,18 +36,11 @@ class HomeserverSettingsViewModel @AssistedInject constructor(
 ) : VectorViewModel<HomeServerSettingsViewState, HomeserverSettingsAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: HomeServerSettingsViewState): HomeserverSettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<HomeserverSettingsViewModel, HomeServerSettingsViewState> {
+        override fun create(initialState: HomeServerSettingsViewState): HomeserverSettingsViewModel
     }
 
-    companion object : MavericksViewModelFactory<HomeserverSettingsViewModel, HomeServerSettingsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: HomeServerSettingsViewState): HomeserverSettingsViewModel? {
-            val fragment: HomeserverSettingsFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.homeserverSettingsViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<HomeserverSettingsViewModel, HomeServerSettingsViewState> by hiltMavericksViewModelFactory()
 
     init {
         setState {
diff --git a/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt
index 91213809de..b2a7b2cbd1 100644
--- a/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt
@@ -18,16 +18,16 @@ package im.vector.app.features.settings.ignored
 
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.platform.VectorViewModelAction
 import kotlinx.coroutines.launch
@@ -49,18 +49,11 @@ class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState:
     VectorViewModel<IgnoredUsersViewState, IgnoredUsersAction, IgnoredUsersViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel
+    interface Factory : MavericksAssistedViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> {
+        override fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel
     }
 
-    companion object : MavericksViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: IgnoredUsersViewState): IgnoredUsersViewModel? {
-            val ignoredUsersFragment: VectorSettingsIgnoredUsersFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return ignoredUsersFragment.ignoredUsersViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> by hiltMavericksViewModelFactory()
 
     init {
         observeIgnoredUsers()
diff --git a/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt
index 1526ac0e69..509014492d 100644
--- a/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt
@@ -36,7 +36,6 @@ import im.vector.app.databinding.FragmentGenericRecyclerBinding
 import javax.inject.Inject
 
 class VectorSettingsIgnoredUsersFragment @Inject constructor(
-        val ignoredUsersViewModelFactory: IgnoredUsersViewModel.Factory,
         private val ignoredUsersController: IgnoredUsersController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
         IgnoredUsersController.Callback {
diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt
index 7368bec397..601574c908 100644
--- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerFragment.kt
@@ -34,10 +34,8 @@ import java.util.Locale
 import javax.inject.Inject
 
 class LocalePickerFragment @Inject constructor(
-        private val viewModelFactory: LocalePickerViewModel.Factory,
         private val controller: LocalePickerController
 ) : VectorBaseFragment<FragmentLocalePickerBinding>(),
-        LocalePickerViewModel.Factory by viewModelFactory,
         LocalePickerController.Listener {
 
     private val viewModel: LocalePickerViewModel by fragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt
index 83858dff6a..d6b35fa4fe 100644
--- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt
@@ -16,15 +16,13 @@
 
 package im.vector.app.features.settings.locale
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.configuration.VectorConfiguration
@@ -37,8 +35,8 @@ class LocalePickerViewModel @AssistedInject constructor(
 ) : VectorViewModel<LocalePickerViewState, LocalePickerAction, LocalePickerViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: LocalePickerViewState): LocalePickerViewModel
+    interface Factory : MavericksAssistedViewModelFactory<LocalePickerViewModel, LocalePickerViewState> {
+        override fun create(initialState: LocalePickerViewState): LocalePickerViewModel
     }
 
     init {
@@ -53,17 +51,7 @@ class LocalePickerViewModel @AssistedInject constructor(
         }
     }
 
-    companion object : MavericksViewModelFactory<LocalePickerViewModel, LocalePickerViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: LocalePickerViewState): LocalePickerViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<LocalePickerViewModel, LocalePickerViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: LocalePickerAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt
index fb3611c721..16c2881653 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt
@@ -39,6 +39,7 @@ import im.vector.app.core.preference.VectorPreference
 import im.vector.app.core.preference.VectorPreferenceCategory
 import im.vector.app.core.preference.VectorSwitchPreference
 import im.vector.app.core.pushers.PushersManager
+import im.vector.app.core.services.GuardServiceStarter
 import im.vector.app.core.utils.isIgnoringBatteryOptimizations
 import im.vector.app.core.utils.requestDisablingBatteryOptimization
 import im.vector.app.features.notifications.NotificationUtils
@@ -64,7 +65,8 @@ import javax.inject.Inject
 class VectorSettingsNotificationPreferenceFragment @Inject constructor(
         private val pushManager: PushersManager,
         private val activeSessionHolder: ActiveSessionHolder,
-        private val vectorPreferences: VectorPreferences
+        private val vectorPreferences: VectorPreferences,
+        private val guardServiceStarter: GuardServiceStarter
 ) : VectorSettingsBaseFragment(),
         BackgroundSyncModeChooserDialog.InteractionListener {
 
@@ -238,14 +240,19 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
             it.isVisible = UPHelper.allowBackgroundSync(requireContext())
         }
 
+        val backgroundSyncEnabled = vectorPreferences.isBackgroundSyncEnabled()
         findPreference<VectorEditTextPreference>(VectorPreferences.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY)?.let {
-            it.isEnabled = vectorPreferences.isBackgroundSyncEnabled()
+            it.isEnabled = backgroundSyncEnabled
             it.summary = secondsToText(vectorPreferences.backgroundSyncTimeOut())
         }
         findPreference<VectorEditTextPreference>(VectorPreferences.SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY)?.let {
-            it.isEnabled = vectorPreferences.isBackgroundSyncEnabled()
+            it.isEnabled = backgroundSyncEnabled
             it.summary = secondsToText(vectorPreferences.backgroundSyncDelay())
         }
+        when {
+            backgroundSyncEnabled -> guardServiceStarter.start()
+            else                  -> guardServiceStarter.stop()
+        }
     }
 
     /**
diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt
index 0801e78197..65c62542bb 100644
--- a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysFragment.kt
@@ -36,7 +36,6 @@ import javax.inject.Inject
 
 // Referenced in vector_settings_notifications.xml
 class PushGatewaysFragment @Inject constructor(
-        val pushGatewaysViewModelFactory: PushGatewaysViewModel.Factory,
         private val epoxyController: PushGateWayController
 ) : VectorBaseFragment<FragmentGenericRecyclerBinding>() {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt
index d8205aada9..1256673364 100644
--- a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt
@@ -17,14 +17,14 @@
 package im.vector.app.features.settings.push
 
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.launch
@@ -38,21 +38,14 @@ data class PushGatewayViewState(
 
 class PushGatewaysViewModel @AssistedInject constructor(@Assisted initialState: PushGatewayViewState,
                                                         private val session: Session) :
-    VectorViewModel<PushGatewayViewState, PushGatewayAction, PushGatewayViewEvents>(initialState) {
+        VectorViewModel<PushGatewayViewState, PushGatewayAction, PushGatewayViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: PushGatewayViewState): PushGatewaysViewModel
+    interface Factory : MavericksAssistedViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> {
+        override fun create(initialState: PushGatewayViewState): PushGatewaysViewModel
     }
 
-    companion object : MavericksViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? {
-            val fragment: PushGatewaysFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.pushGatewaysViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> by hiltMavericksViewModelFactory()
 
     init {
         observePushers()
diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt
index 745d71fd41..0b6b72bb10 100644
--- a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt
@@ -18,7 +18,8 @@ package im.vector.app.features.settings.push
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
-import im.vector.app.core.di.HasScreenInjector
+import dagger.hilt.EntryPoints
+import im.vector.app.core.di.SingletonEntryPoint
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -34,7 +35,7 @@ class PushRulesViewModel(initialState: PushRulesViewState) :
     companion object : MavericksViewModelFactory<PushRulesViewModel, PushRulesViewState> {
 
         override fun initialState(viewModelContext: ViewModelContext): PushRulesViewState? {
-            val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
+            val session = EntryPoints.get(viewModelContext.app(), SingletonEntryPoint::class.java).activeSessionHolder().getActiveSession()
             val rules = session.getPushRules().getAllRules()
             return PushRulesViewState(rules)
         }
diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt
index 384348b85d..a893f0f508 100644
--- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsFragment.kt
@@ -43,12 +43,10 @@ import org.matrix.android.sdk.api.session.identity.ThreePid
 import javax.inject.Inject
 
 class ThreePidsSettingsFragment @Inject constructor(
-        private val viewModelFactory: ThreePidsSettingsViewModel.Factory,
         private val epoxyController: ThreePidsSettingsController
 ) :
         VectorBaseFragment<FragmentGenericRecyclerBinding>(),
         OnBackPressed,
-        ThreePidsSettingsViewModel.Factory by viewModelFactory,
         ThreePidsSettingsController.InteractionListener {
 
     private val viewModel: ThreePidsSettingsViewModel by fragmentViewModel()
diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt
index cd0d74a288..12ff436ccb 100644
--- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt
@@ -16,16 +16,15 @@
 
 package im.vector.app.features.settings.threepids
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
@@ -79,21 +78,11 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ThreePidsSettingsViewState): ThreePidsSettingsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ThreePidsSettingsViewModel, ThreePidsSettingsViewState> {
+        override fun create(initialState: ThreePidsSettingsViewState): ThreePidsSettingsViewModel
     }
 
-    companion object : MavericksViewModelFactory<ThreePidsSettingsViewModel, ThreePidsSettingsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: ThreePidsSettingsViewState): ThreePidsSettingsViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<ThreePidsSettingsViewModel, ThreePidsSettingsViewState> by hiltMavericksViewModelFactory()
 
     init {
         observeThreePids()
diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBackgroundRestrictions.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBackgroundRestrictions.kt
index dec08b49d1..d42aee849d 100644
--- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBackgroundRestrictions.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBackgroundRestrictions.kt
@@ -18,14 +18,14 @@ package im.vector.app.features.settings.troubleshoot
 import android.content.Intent
 import android.net.ConnectivityManager
 import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
 import androidx.core.content.getSystemService
 import androidx.core.net.ConnectivityManagerCompat
+import androidx.fragment.app.FragmentActivity
 import im.vector.app.R
 import im.vector.app.core.resources.StringProvider
 import javax.inject.Inject
 
-class TestBackgroundRestrictions @Inject constructor(private val context: AppCompatActivity,
+class TestBackgroundRestrictions @Inject constructor(private val context: FragmentActivity,
                                                      private val stringProvider: StringProvider) :
     TroubleshootTest(R.string.settings_troubleshoot_test_bg_restricted_title) {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBatteryOptimization.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBatteryOptimization.kt
index 5f5eb42e94..fbbfc56539 100644
--- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBatteryOptimization.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestBatteryOptimization.kt
@@ -17,7 +17,7 @@ package im.vector.app.features.settings.troubleshoot
 
 import android.content.Intent
 import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
 import im.vector.app.R
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.utils.isIgnoringBatteryOptimizations
@@ -25,7 +25,7 @@ import im.vector.app.core.utils.requestDisablingBatteryOptimization
 import javax.inject.Inject
 
 class TestBatteryOptimization @Inject constructor(
-        private val context: AppCompatActivity,
+        private val context: FragmentActivity,
         private val stringProvider: StringProvider
 ) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestNewEndpoint.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestNewEndpoint.kt
index 7a748d5fab..84a001716a 100644
--- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestNewEndpoint.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestNewEndpoint.kt
@@ -17,7 +17,7 @@ package im.vector.app.features.settings.troubleshoot
 
 import android.content.Intent
 import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
 import im.vector.app.R
 import im.vector.app.core.pushers.UPHelper
 import im.vector.app.core.resources.StringProvider
@@ -26,7 +26,7 @@ import javax.inject.Inject
 /*
 * Test that app can successfully retrieve a new endpoint
  */
-class TestNewEndpoint @Inject constructor(private val context: AppCompatActivity,
+class TestNewEndpoint @Inject constructor(private val context: FragmentActivity,
                                           private val stringProvider: StringProvider
                                           ) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_title) {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt
index 4c7c0e445d..d8c35a071f 100644
--- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt
@@ -17,7 +17,7 @@ package im.vector.app.features.settings.troubleshoot
 
 import android.content.Intent
 import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.error.ErrorFormatter
@@ -35,7 +35,7 @@ import javax.inject.Inject
 /**
  * Test Push by asking the Push Gateway to send a Push back
  */
-class TestPushFromPushGateway @Inject constructor(private val context: AppCompatActivity,
+class TestPushFromPushGateway @Inject constructor(private val context: FragmentActivity,
                                                   private val stringProvider: StringProvider,
                                                   private val errorFormatter: ErrorFormatter,
                                                   private val pushersManager: PushersManager,
diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestSystemSettings.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestSystemSettings.kt
index d4f089b943..42f506d4a6 100644
--- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestSystemSettings.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestSystemSettings.kt
@@ -15,10 +15,10 @@
  */
 package im.vector.app.features.settings.troubleshoot
 
-import android.content.Context
 import android.content.Intent
 import androidx.activity.result.ActivityResultLauncher
 import androidx.core.app.NotificationManagerCompat
+import androidx.fragment.app.FragmentActivity
 import im.vector.app.R
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.utils.startNotificationSettingsIntent
@@ -27,7 +27,7 @@ import javax.inject.Inject
 /**
  * Checks if notifications are enable in the system settings for this app.
  */
-class TestSystemSettings @Inject constructor(private val context: Context,
+class TestSystemSettings @Inject constructor(private val context: FragmentActivity,
                                              private val stringProvider: StringProvider) :
     TroubleshootTest(R.string.settings_troubleshoot_test_system_settings_title) {
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestTokenRegistration.kt
index 4caf2f3498..9f8b015a7d 100644
--- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestTokenRegistration.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestTokenRegistration.kt
@@ -17,7 +17,7 @@ package im.vector.app.features.settings.troubleshoot
 
 import android.content.Intent
 import androidx.activity.result.ActivityResultLauncher
-import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.FragmentActivity
 import androidx.lifecycle.Observer
 import androidx.work.WorkInfo
 import androidx.work.WorkManager
@@ -32,7 +32,7 @@ import javax.inject.Inject
 /**
  * Force registration of the token to HomeServer
  */
-class TestTokenRegistration @Inject constructor(private val context: AppCompatActivity,
+class TestTokenRegistration @Inject constructor(private val context: FragmentActivity,
                                                 private val stringProvider: StringProvider,
                                                 private val pushersManager: PushersManager,
                                                 private val activeSessionHolder: ActiveSessionHolder) :
diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt
index b9d3b1ba14..09321ad27e 100644
--- a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt
@@ -17,12 +17,14 @@
 package im.vector.app.features.share
 
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 
+@AndroidEntryPoint
 class IncomingShareActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
 
     override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt
index 2132ba7989..d5fd3050e9 100644
--- a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt
@@ -50,7 +50,6 @@ import javax.inject.Inject
  * The user can select multiple rooms to send the data to
  */
 class IncomingShareFragment @Inject constructor(
-        val incomingShareViewModelFactory: IncomingShareViewModel.Factory,
         private val incomingShareController: IncomingShareController,
         private val sessionHolder: ActiveSessionHolder
 ) :
diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt
index b476065035..4a413ad8ba 100644
--- a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt
@@ -16,12 +16,12 @@
 
 package im.vector.app.features.share
 
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.toggle
 import im.vector.app.core.platform.VectorViewModel
@@ -46,18 +46,11 @@ class IncomingShareViewModel @AssistedInject constructor(
     VectorViewModel<IncomingShareViewState, IncomingShareAction, IncomingShareViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: IncomingShareViewState): IncomingShareViewModel
+    interface Factory : MavericksAssistedViewModelFactory<IncomingShareViewModel, IncomingShareViewState> {
+        override fun create(initialState: IncomingShareViewState): IncomingShareViewModel
     }
 
-    companion object : MavericksViewModelFactory<IncomingShareViewModel, IncomingShareViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: IncomingShareViewState): IncomingShareViewModel? {
-            val fragment: IncomingShareFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.incomingShareViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<IncomingShareViewModel, IncomingShareViewState> by hiltMavericksViewModelFactory()
 
     private val filterStream = MutableStateFlow("")
 
diff --git a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt
index 6f05a73f13..ee7557b402 100644
--- a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt
@@ -19,6 +19,7 @@ package im.vector.app.features.signout.hard
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySignedOutBinding
 import im.vector.app.features.MainActivity
@@ -29,6 +30,7 @@ import timber.log.Timber
 /**
  * In this screen, the user is viewing a message informing that he has been logged out
  */
+@AndroidEntryPoint
 class SignedOutActivity : VectorBaseActivity<ActivitySignedOutBinding>() {
 
     override fun getBinding() = ActivitySignedOutBinding.inflate(layoutInflater)
diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt
index 72b9a278e2..4fba8fc3de 100644
--- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity.kt
@@ -23,8 +23,8 @@ import androidx.fragment.app.FragmentManager
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.features.MainActivity
@@ -39,23 +39,18 @@ import javax.inject.Inject
  * In this screen, the user is viewing a message informing that he has been logged out
  * Extends LoginActivity to get the login with SSO and forget password functionality for (nearly) free
  */
+@AndroidEntryPoint
 class SoftLogoutActivity : LoginActivity() {
 
     private val softLogoutViewModel: SoftLogoutViewModel by viewModel()
 
-    @Inject lateinit var softLogoutViewModelFactory: SoftLogoutViewModel.Factory
     @Inject lateinit var session: Session
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         super.initUiAndData()
 
-        softLogoutViewModel.subscribe(this) {
+        softLogoutViewModel.onEach {
             updateWithState(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity2.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity2.kt
index 3689bff0c7..26500b60f0 100644
--- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity2.kt
+++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutActivity2.kt
@@ -23,8 +23,8 @@ import androidx.fragment.app.FragmentManager
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.features.MainActivity
@@ -41,23 +41,18 @@ import javax.inject.Inject
  *
  * This is just a copy of SoftLogoutActivity2, which extends LoginActivity2
  */
+@AndroidEntryPoint
 class SoftLogoutActivity2 : LoginActivity2() {
 
     private val softLogoutViewModel: SoftLogoutViewModel by viewModel()
 
-    @Inject lateinit var softLogoutViewModelFactory: SoftLogoutViewModel.Factory
     @Inject lateinit var session: Session
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         super.initUiAndData()
 
-        softLogoutViewModel.subscribe(this) {
+        softLogoutViewModel.onEach {
             updateWithState(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt
index 2aa7f15172..016d340f80 100644
--- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutFragment.kt
@@ -55,7 +55,7 @@ class SoftLogoutFragment @Inject constructor(
 
         setupRecyclerView()
 
-        softLogoutViewModel.subscribe(this) { softLogoutViewState ->
+        softLogoutViewModel.onEach { softLogoutViewState ->
             softLogoutController.update(softLogoutViewState)
             when (val mode = softLogoutViewState.asyncHomeServerLoginFlowRequest.invoke()) {
                 is LoginMode.SsoAndPassword -> {
diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt
index dfc483a813..52986a1f3b 100644
--- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt
@@ -27,6 +27,8 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.hasUnsavedKeys
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.login.LoginMode
@@ -47,11 +49,11 @@ class SoftLogoutViewModel @AssistedInject constructor(
 ) : VectorViewModel<SoftLogoutViewState, SoftLogoutAction, SoftLogoutViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SoftLogoutViewState): SoftLogoutViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SoftLogoutViewModel, SoftLogoutViewState> {
+        override fun create(initialState: SoftLogoutViewState): SoftLogoutViewModel
     }
 
-    companion object : MavericksViewModelFactory<SoftLogoutViewModel, SoftLogoutViewState> {
+    companion object : MavericksViewModelFactory<SoftLogoutViewModel, SoftLogoutViewState> by hiltMavericksViewModelFactory() {
 
         override fun initialState(viewModelContext: ViewModelContext): SoftLogoutViewState? {
             val activity: SoftLogoutActivity = (viewModelContext as ActivityViewModelContext).activity()
@@ -64,12 +66,6 @@ class SoftLogoutViewModel @AssistedInject constructor(
                     hasUnsavedKeys = activity.session.hasUnsavedKeys()
             )
         }
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SoftLogoutViewState): SoftLogoutViewModel? {
-            val activity: SoftLogoutActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.softLogoutViewModelFactory.create(state)
-        }
     }
 
     init {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/InviteRoomSpaceChooserBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/InviteRoomSpaceChooserBottomSheet.kt
index cf7871bc99..b4c1e67cfb 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/InviteRoomSpaceChooserBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/InviteRoomSpaceChooserBottomSheet.kt
@@ -23,14 +23,15 @@ import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
 import com.airbnb.mvrx.args
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetSpaceInviteChooserBinding
 import kotlinx.parcelize.Parcelize
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class InviteRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceInviteChooserBinding>() {
 
     @Parcelize
@@ -53,10 +54,6 @@ class InviteRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<Bo
 
     var interactionListener: InteractionListener? = null
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetSpaceInviteChooserBinding {
         return BottomSheetSpaceInviteChooserBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/LeaveSpaceBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/LeaveSpaceBottomSheet.kt
index 7afb0babae..a292b64ddd 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/LeaveSpaceBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/LeaveSpaceBottomSheet.kt
@@ -26,14 +26,14 @@ import android.view.ViewGroup
 import androidx.core.text.toSpannable
 import androidx.core.view.isInvisible
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.parentFragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.widget.checkedChanges
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.registerStartForActivityResult
 import im.vector.app.core.extensions.setTextOrHide
@@ -43,12 +43,15 @@ import im.vector.app.core.utils.styleMatchingText
 import im.vector.app.databinding.BottomSheetLeaveSpaceBinding
 import im.vector.app.features.displayname.getBestName
 import im.vector.app.features.spaces.leave.SpaceLeaveAdvancedActivity
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import me.gujun.android.span.span
 import org.matrix.android.sdk.api.util.toMatrixItem
+import reactivecircus.flowbinding.android.widget.checkedChanges
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLeaveSpaceBinding>() {
 
     val settingsViewModel: SpaceMenuViewModel by parentFragmentViewModel()
@@ -60,10 +63,6 @@ class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLea
     @Inject lateinit var colorProvider: ColorProvider
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     @Parcelize
     data class Args(
             val spaceId: String
@@ -85,8 +84,7 @@ class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLea
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         views.autoLeaveRadioGroup.checkedChanges()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe {
+                .onEach {
                     when (it) {
                         views.leaveAll.id      -> {
                             settingsViewModel.handle(SpaceLeaveViewAction.SetAutoLeaveAll)
@@ -103,7 +101,7 @@ class LeaveSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetLea
                         }
                     }
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.leaveButton.debouncedClicks {
             settingsViewModel.handle(SpaceLeaveViewAction.LeaveSpace)
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt
index 1844e8e9ca..44acfa8ee3 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt
@@ -24,8 +24,8 @@ import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.toMvRxBundle
 import im.vector.app.core.platform.SimpleFragmentActivity
 import im.vector.app.features.spaces.create.ChoosePrivateSpaceTypeFragment
@@ -39,16 +39,9 @@ import im.vector.app.features.spaces.create.CreateSpaceState
 import im.vector.app.features.spaces.create.CreateSpaceViewModel
 import im.vector.app.features.spaces.create.SpaceTopology
 import im.vector.app.features.spaces.create.SpaceType
-import javax.inject.Inject
 
-class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Factory {
-
-    @Inject lateinit var viewModelFactory: CreateSpaceViewModel.Factory
-
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
+@AndroidEntryPoint
+class SpaceCreationActivity : SimpleFragmentActivity() {
 
     val viewModel: CreateSpaceViewModel by viewModel()
 
@@ -78,7 +71,7 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
     override fun initUiAndData() {
         super.initUiAndData()
 
-        viewModel.subscribe(this) {
+        viewModel.onEach {
             renderState(it)
         }
 
@@ -187,6 +180,4 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
             return data?.extras?.getBoolean(RESULT_DATA_CREATED_SPACE_IS_JUST_ME, false) == true
         }
     }
-
-    override fun create(initialState: CreateSpaceState): CreateSpaceViewModel = viewModelFactory.create(initialState)
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt
index 47e4c6420b..780183d866 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt
@@ -23,8 +23,8 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
@@ -32,18 +32,11 @@ import im.vector.app.features.matrixto.MatrixToBottomSheet
 import im.vector.app.features.navigation.Navigator
 import im.vector.app.features.spaces.explore.SpaceDirectoryArgs
 import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
-import im.vector.app.features.spaces.explore.SpaceDirectoryState
 import im.vector.app.features.spaces.explore.SpaceDirectoryViewEvents
 import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel
-import javax.inject.Inject
 
-class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceDirectoryViewModel.Factory, MatrixToBottomSheet.InteractionListener {
-
-    @Inject lateinit var spaceDirectoryViewModelFactory: SpaceDirectoryViewModel.Factory
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
+@AndroidEntryPoint
+class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), MatrixToBottomSheet.InteractionListener {
 
     override fun getBinding(): ActivitySimpleBinding = ActivitySimpleBinding.inflate(layoutInflater)
 
@@ -113,9 +106,6 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD
         }
     }
 
-    override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel =
-            spaceDirectoryViewModelFactory.create(initialState)
-
     override fun mxToBottomSheetNavigateToRoom(roomId: String) {
         navigator.openRoom(this, roomId)
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt
index 0a67977e6c..dff98722eb 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt
@@ -39,12 +39,11 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import javax.inject.Inject
 
 class SpaceListFragment @Inject constructor(
-        val spaceListViewModelFactory: SpacesListViewModel.Factory,
         private val spaceController: SpaceSummaryController
 ) : VectorBaseFragment<FragmentGroupListBinding>(), SpaceSummaryController.Callback {
 
     private lateinit var sharedActionViewModel: HomeSharedActionViewModel
-    private val viewModel: SpacesListViewModel by fragmentViewModel()
+    private val viewModel: SpaceListViewModel by fragmentViewModel()
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGroupListBinding {
         return FragmentGroupListBinding.inflate(inflater, container, false)
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt
similarity index 89%
rename from vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt
rename to vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt
index ba06d4920e..11597e50f7 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt
@@ -17,16 +17,16 @@
 package im.vector.app.features.spaces
 
 import androidx.lifecycle.asFlow
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
 import im.vector.app.RoomGroupingMethod
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.invite.AutoAcceptInvites
 import im.vector.app.features.session.coroutineScope
@@ -35,6 +35,7 @@ import im.vector.app.group
 import im.vector.app.space
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
@@ -59,26 +60,19 @@ import org.matrix.android.sdk.api.session.space.model.TopLevelSpaceComparator
 import org.matrix.android.sdk.api.util.toMatrixItem
 import org.matrix.android.sdk.flow.flow
 
-class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: SpaceListViewState,
-                                                      private val appStateHandler: AppStateHandler,
-                                                      private val session: Session,
-                                                      private val vectorPreferences: VectorPreferences,
-                                                      private val autoAcceptInvites: AutoAcceptInvites
+class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: SpaceListViewState,
+                                                     private val appStateHandler: AppStateHandler,
+                                                     private val session: Session,
+                                                     private val vectorPreferences: VectorPreferences,
+                                                     private val autoAcceptInvites: AutoAcceptInvites
 ) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceListViewState): SpacesListViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceListViewModel, SpaceListViewState> {
+        override fun create(initialState: SpaceListViewState): SpaceListViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpacesListViewModel, SpaceListViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SpaceListViewState): SpacesListViewModel {
-            val groupListFragment: SpaceListFragment = (viewModelContext as FragmentViewModelContext).fragment()
-            return groupListFragment.spaceListViewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceListViewModel, SpaceListViewState> by hiltMavericksViewModelFactory()
 
 //    private var currentGroupingMethod : RoomGroupingMethod? = null
 
@@ -96,14 +90,11 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
 //        observeSelectionState()
         appStateHandler.selectedRoomGroupingObservable
                 .distinctUntilChanged()
-                .subscribe {
-                    setState {
-                        copy(
-                                selectedGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
-                        )
-                    }
+                .setOnEach {
+                    copy(
+                            selectedGroupingMethod = it.orNull() ?: RoomGroupingMethod.BySpace(null)
+                    )
                 }
-                .disposeOnClear()
 
         session.getGroupSummariesLive(groupSummaryQueryParams {})
                 .asFlow()
@@ -121,7 +112,6 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
                 }, sortOrder = RoomSortOrder.NONE
         ).asFlow()
                 .sample(300)
-                .flowOn(Dispatchers.Default)
                 .onEach {
                     val inviteCount = if (autoAcceptInvites.hideInvites) {
                         0
@@ -148,7 +138,9 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
                                 homeAggregateCount = counts
                         )
                     }
-                }.launchIn(viewModelScope)
+                }
+                .flowOn(Dispatchers.Default)
+                .launchIn(viewModelScope)
     }
 
     override fun handle(action: SpaceListAction) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt
index 887c93afd4..2e9af2eacb 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt
@@ -16,18 +16,17 @@
 
 package im.vector.app.features.spaces
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
@@ -52,21 +51,11 @@ class SpaceMenuViewModel @AssistedInject constructor(
 ) : VectorViewModel<SpaceMenuState, SpaceLeaveViewAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceMenuState): SpaceMenuViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceMenuViewModel, SpaceMenuState> {
+        override fun create(initialState: SpaceMenuState): SpaceMenuViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpaceMenuViewModel, SpaceMenuState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SpaceMenuState): SpaceMenuViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceMenuViewModel, SpaceMenuState> by hiltMavericksViewModelFactory()
 
     init {
         val roomSummary = session.getRoomSummary(initialState.spaceId)
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt
index 59166529b9..b616cdcce7 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt
@@ -19,14 +19,19 @@ package im.vector.app.features.spaces
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Mavericks
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.spaces.preview.SpacePreviewArgs
 import im.vector.app.features.spaces.preview.SpacePreviewFragment
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
+@AndroidEntryPoint
 class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
 
     lateinit var sharedActionViewModel: SpacePreviewSharedActionViewModel
@@ -37,8 +42,8 @@ class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
         super.onCreate(savedInstanceState)
         sharedActionViewModel = viewModelProvider.get(SpacePreviewSharedActionViewModel::class.java)
         sharedActionViewModel
-                .observe()
-                .subscribe { action ->
+                .stream()
+                .onEach { action ->
                     when (action) {
                         SpacePreviewSharedAction.DismissAction -> finish()
                         SpacePreviewSharedAction.ShowModalLoading -> showWaitingView()
@@ -46,7 +51,7 @@ class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
                         is SpacePreviewSharedAction.ShowErrorMessage -> action.error?.let { showSnackbar(it) }
                     }
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
 
         if (isFirstCreation()) {
             val simpleName = SpacePreviewFragment::class.java.simpleName
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt
index 040f1f9057..7449868292 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceSettingsMenuBottomSheet.kt
@@ -26,7 +26,7 @@ import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetSpaceSettingsBinding
@@ -46,12 +46,12 @@ data class SpaceBottomSheetSettingsArgs(
         val spaceId: String
 ) : Parcelable
 
-class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>(), SpaceMenuViewModel.Factory {
+@AndroidEntryPoint
+class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>() {
 
     @Inject lateinit var navigator: Navigator
     @Inject lateinit var avatarRenderer: AvatarRenderer
     @Inject lateinit var bugReporter: BugReporter
-    @Inject lateinit var viewModelFactory: SpaceMenuViewModel.Factory
 
     private val spaceArgs: SpaceBottomSheetSettingsArgs by args()
 
@@ -65,10 +65,6 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
 
     override val showExpanded = true
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     var isLastAdmin: Boolean = false
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetSpaceSettingsBinding {
@@ -139,8 +135,4 @@ class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomS
             }
         }
     }
-
-    override fun create(initialState: SpaceMenuState): SpaceMenuViewModel {
-        return viewModelFactory.create(initialState)
-    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAdd3pidInvitesFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAdd3pidInvitesFragment.kt
index 6dc3ad8c21..4328c46188 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAdd3pidInvitesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAdd3pidInvitesFragment.kt
@@ -50,7 +50,7 @@ class CreateSpaceAdd3pidInvitesFragment @Inject constructor(
         views.recyclerView.configureWith(epoxyController)
         epoxyController.listener = this
 
-        sharedViewModel.subscribe(this) {
+        sharedViewModel.onEach {
             invalidateState(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDefaultRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDefaultRoomsFragment.kt
index 53a4ee689b..4ed7e91417 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDefaultRoomsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDefaultRoomsFragment.kt
@@ -46,7 +46,7 @@ class CreateSpaceDefaultRoomsFragment @Inject constructor(
         views.recyclerView.configureWith(epoxyController)
         epoxyController.listener = this
 
-        sharedViewModel.subscribe(this) {
+        sharedViewModel.onEach {
             epoxyController.setData(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt
index 544c33948b..920ceed33c 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt
@@ -50,7 +50,7 @@ class CreateSpaceDetailsFragment @Inject constructor(
         views.recyclerView.configureWith(epoxyController)
         epoxyController.listener = this
 
-        sharedViewModel.subscribe(this) {
+        sharedViewModel.onEach {
             epoxyController.setData(it)
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
index 34cc72b03f..8ddeab3223 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
@@ -16,10 +16,7 @@
 
 package im.vector.app.features.spaces.create
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
@@ -29,6 +26,8 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.isEmail
@@ -76,8 +75,8 @@ class CreateSpaceViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: CreateSpaceState): CreateSpaceViewModel
+    interface Factory : MavericksAssistedViewModelFactory<CreateSpaceViewModel, CreateSpaceState> {
+        override fun create(initialState: CreateSpaceState): CreateSpaceViewModel
     }
 
     private fun startListenToIdentityManager() {
@@ -93,17 +92,9 @@ class CreateSpaceViewModel @AssistedInject constructor(
         super.onCleared()
     }
 
-    companion object : MavericksViewModelFactory<CreateSpaceViewModel, CreateSpaceState> {
+    companion object : MavericksViewModelFactory<CreateSpaceViewModel, CreateSpaceState> by hiltMavericksViewModelFactory() {
 
-        override fun create(viewModelContext: ViewModelContext, state: CreateSpaceState): CreateSpaceViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-
-        override fun initialState(viewModelContext: ViewModelContext): CreateSpaceState? {
+        override fun initialState(viewModelContext: ViewModelContext): CreateSpaceState {
             return CreateSpaceState(
                     defaultRooms = mapOf(
                             0 to viewModelContext.activity.getString(R.string.create_spaces_default_public_room_name),
diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt
index 5e2537f587..d7bdf4f511 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt
@@ -16,17 +16,16 @@
 
 package im.vector.app.features.spaces.explore
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
 import kotlinx.coroutines.Dispatchers
@@ -52,19 +51,11 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
 ) : VectorViewModel<SpaceDirectoryState, SpaceDirectoryViewAction, SpaceDirectoryViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceDirectoryViewModel, SpaceDirectoryState> {
+        override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpaceDirectoryViewModel, SpaceDirectoryState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpaceDirectoryState): SpaceDirectoryViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceDirectoryViewModel, SpaceDirectoryState> by hiltMavericksViewModelFactory()
 
     init {
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheet.kt
index 4f8d0b6c2f..bd6dec7c4b 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheet.kt
@@ -30,8 +30,8 @@ import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.platform.ButtonStateView
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.core.utils.toast
@@ -43,7 +43,8 @@ import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
-class SpaceInviteBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetInvitedToSpaceBinding>(), SpaceInviteBottomSheetViewModel.Factory {
+@AndroidEntryPoint
+class SpaceInviteBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetInvitedToSpaceBinding>() {
 
     interface InteractionListener {
         fun spaceInviteBottomSheetOnAccept(spaceId: String)
@@ -57,22 +58,11 @@ class SpaceInviteBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetIn
             val spaceId: String
     ) : Parcelable
 
-    @Inject
-    lateinit var avatarRenderer: AvatarRenderer
-
-    @Inject
-    lateinit var spaceCardRenderer: SpaceCardRenderer
+    @Inject lateinit var avatarRenderer: AvatarRenderer
+    @Inject lateinit var spaceCardRenderer: SpaceCardRenderer
 
     private val viewModel: SpaceInviteBottomSheetViewModel by fragmentViewModel(SpaceInviteBottomSheetViewModel::class)
 
-    @Inject lateinit var viewModelFactory: SpaceInviteBottomSheetViewModel.Factory
-
-    override fun create(initialState: SpaceInviteBottomSheetState) = viewModelFactory.create(initialState)
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override val showExpanded = true
 
     private val inviteArgs: Args by args()
diff --git a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt
index 00fb6c4054..79ad043813 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt
@@ -17,17 +17,16 @@
 package im.vector.app.features.spaces.invite
 
 import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.session.coroutineScope
@@ -93,20 +92,11 @@ class SpaceInviteBottomSheetViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceInviteBottomSheetState): SpaceInviteBottomSheetViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceInviteBottomSheetViewModel, SpaceInviteBottomSheetState> {
+        override fun create(initialState: SpaceInviteBottomSheetState): SpaceInviteBottomSheetViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpaceInviteBottomSheetViewModel, SpaceInviteBottomSheetState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: SpaceInviteBottomSheetState): SpaceInviteBottomSheetViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceInviteBottomSheetViewModel, SpaceInviteBottomSheetState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: SpaceInviteBottomSheetAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SelectChildrenController.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SelectChildrenController.kt
index 39d1d72675..6260c136d9 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/leave/SelectChildrenController.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SelectChildrenController.kt
@@ -16,6 +16,7 @@
 
 package im.vector.app.features.spaces.leave
 
+import androidx.core.util.Predicate
 import com.airbnb.epoxy.TypedEpoxyController
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
@@ -27,7 +28,6 @@ import im.vector.app.core.epoxy.noResultItem
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.home.AvatarRenderer
 import im.vector.app.features.spaces.manage.roomSelectionItem
-import io.reactivex.functions.Predicate
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.util.toMatrixItem
diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt
index 762abf10cb..69de39e436 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt
@@ -28,8 +28,8 @@ import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.hideKeyboard
@@ -40,24 +40,16 @@ import im.vector.app.databinding.ActivitySimpleLoadingBinding
 import im.vector.app.features.spaces.SpaceBottomSheetSettingsArgs
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class SpaceLeaveAdvancedActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
-        SpaceLeaveAdvancedViewModel.Factory,
         ToolbarConfigurable {
 
     override fun getBinding(): ActivitySimpleLoadingBinding = ActivitySimpleLoadingBinding.inflate(layoutInflater)
 
     val leaveViewModel: SpaceLeaveAdvancedViewModel by viewModel()
 
-    @Inject lateinit var viewModelFactory: SpaceLeaveAdvancedViewModel.Factory
     @Inject lateinit var errorFormatter: ErrorFormatter
 
-    override fun create(initialState: SpaceLeaveAdvanceViewState) = viewModelFactory.create(initialState)
-
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
     override fun showWaitingView(text: String?) {
         hideKeyboard()
         views.waitingView.waitingStatusText.isGone = views.waitingView.waitingStatusText.text.isNullOrBlank()
@@ -94,7 +86,7 @@ class SpaceLeaveAdvancedActivity : VectorBaseActivity<ActivitySimpleLoadingBindi
     override fun initUiAndData() {
         super.initUiAndData()
         waitingView = views.waitingView.waitingView
-        leaveViewModel.subscribe(this) { state ->
+        leaveViewModel.onEach { state ->
             when (state.leaveState) {
                 is Loading -> {
                     showWaitingView()
diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt
index e78d90c6d9..b84f870f34 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt
@@ -20,16 +20,18 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.appcompat.queryTextChanges
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentSpaceLeaveAdvancedBinding
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.appcompat.queryTextChanges
 import javax.inject.Inject
 
 class SpaceLeaveAdvancedFragment @Inject constructor(
@@ -54,11 +56,11 @@ class SpaceLeaveAdvancedFragment @Inject constructor(
         }
 
         views.publicRoomsFilter.queryTextChanges()
-                .debounce(100, TimeUnit.MILLISECONDS)
-                .subscribeBy {
+                .debounce(100)
+                .onEach {
                     viewModel.handle(SpaceLeaveAdvanceViewAction.UpdateFilter(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     override fun onDestroyView() {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt
index 3d24cf6225..e9b75836e9 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt
@@ -16,18 +16,17 @@
 
 package im.vector.app.features.spaces.leave
 
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.AppStateHandler
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.flow.launchIn
@@ -127,17 +126,9 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceLeaveAdvancedViewModel, SpaceLeaveAdvanceViewState> {
+        override fun create(initialState: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpaceLeaveAdvancedViewModel, SpaceLeaveAdvanceViewState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceLeaveAdvancedViewModel, SpaceLeaveAdvanceViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt
index 0512a478a1..9bf304fa1c 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt
@@ -22,6 +22,7 @@ import android.view.Menu
 import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.ConcatAdapter
 import androidx.recyclerview.widget.LinearLayoutManager
 import com.airbnb.mvrx.Loading
@@ -29,24 +30,24 @@ import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.jakewharton.rxbinding3.appcompat.queryTextChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.platform.OnBackPressed
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentSpaceAddRoomsBinding
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.appcompat.queryTextChanges
 import javax.inject.Inject
 
 class SpaceAddRoomFragment @Inject constructor(
         private val spaceEpoxyController: AddRoomListController,
         private val roomEpoxyController: AddRoomListController,
         private val dmEpoxyController: AddRoomListController,
-        private val viewModelFactory: SpaceAddRoomsViewModel.Factory
 ) : VectorBaseFragment<FragmentSpaceAddRoomsBinding>(),
-        OnBackPressed, AddRoomListController.Listener, SpaceAddRoomsViewModel.Factory {
+        OnBackPressed, AddRoomListController.Listener {
 
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
             FragmentSpaceAddRoomsBinding.inflate(layoutInflater, container, false)
@@ -55,9 +56,6 @@ class SpaceAddRoomFragment @Inject constructor(
 
     private val sharedViewModel: SpaceManageSharedViewModel by activityViewModel()
 
-    override fun create(initialState: SpaceAddRoomsState): SpaceAddRoomsViewModel =
-            viewModelFactory.create(initialState)
-
     override fun getMenuRes(): Int = R.menu.menu_space_add_room
 
     private var saveNeeded = false
@@ -76,11 +74,11 @@ class SpaceAddRoomFragment @Inject constructor(
         setupRecyclerView()
 
         views.publicRoomsFilter.queryTextChanges()
-                .debounce(100, TimeUnit.MILLISECONDS)
-                .subscribeBy {
+                .debounce(100)
+                .onEach {
                     viewModel.handle(SpaceAddRoomActions.UpdateFilter(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         spaceEpoxyController.subHeaderText = getString(R.string.spaces_feeling_experimental_subspace)
         viewModel.selectionListLiveData.observe(viewLifecycleOwner) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt
index bf062ce0a8..8fa269d439 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt
@@ -19,16 +19,15 @@ package im.vector.app.features.spaces.manage
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.viewModelScope
 import androidx.paging.PagedList
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
@@ -55,10 +54,12 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
 ) : VectorViewModel<SpaceAddRoomsState, SpaceAddRoomActions, SpaceAddRoomsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceAddRoomsState): SpaceAddRoomsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceAddRoomsViewModel, SpaceAddRoomsState> {
+        override fun create(initialState: SpaceAddRoomsState): SpaceAddRoomsViewModel
     }
 
+    companion object : MavericksViewModelFactory<SpaceAddRoomsViewModel, SpaceAddRoomsState> by hiltMavericksViewModelFactory()
+
     val updatableLiveSpacePageResult: UpdatableLivePageResult by lazy {
         session.getFilteredPagedRoomSummariesLive(
                 roomSummaryQueryParams {
@@ -132,16 +133,6 @@ class SpaceAddRoomsViewModel @AssistedInject constructor(
         }
     }
 
-    companion object : MavericksViewModelFactory<SpaceAddRoomsViewModel, SpaceAddRoomsState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpaceAddRoomsState): SpaceAddRoomsViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
-
     fun canGoBack(): Boolean {
         val needToSave = selectionList.values.any { it }
         if (needToSave) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceChildInfoMatchFilter.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceChildInfoMatchFilter.kt
index 66878a4011..45fdbca598 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceChildInfoMatchFilter.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceChildInfoMatchFilter.kt
@@ -16,7 +16,7 @@
 
 package im.vector.app.features.spaces.manage
 
-import io.reactivex.functions.Predicate
+import androidx.core.util.Predicate
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt
index f45f9099bb..932110d0e3 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt
@@ -22,12 +22,13 @@ import android.os.Bundle
 import android.os.Parcelable
 import androidx.core.view.isGone
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragmentToBackstack
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.hideKeyboard
@@ -41,8 +42,9 @@ import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
 import im.vector.app.features.roomprofile.RoomProfileArgs
 import im.vector.app.features.roomprofile.alias.RoomAliasFragment
 import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
-import javax.inject.Inject
 
 @Parcelize
 data class SpaceManageArgs(
@@ -50,17 +52,12 @@ data class SpaceManageArgs(
         val manageType: ManageType
 ) : Parcelable
 
+@AndroidEntryPoint
 class SpaceManageActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
-        ToolbarConfigurable,
-        SpaceManageSharedViewModel.Factory {
+        ToolbarConfigurable {
 
-    @Inject lateinit var sharedViewModelFactory: SpaceManageSharedViewModel.Factory
     private lateinit var sharedDirectoryActionViewModel: RoomDirectorySharedActionViewModel
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(): ActivitySimpleLoadingBinding = ActivitySimpleLoadingBinding.inflate(layoutInflater)
 
     override fun getTitleRes(): Int = R.string.space_add_existing_rooms
@@ -86,14 +83,14 @@ class SpaceManageActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
 
         sharedDirectoryActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
         sharedDirectoryActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         is RoomDirectorySharedAction.Back,
                         is RoomDirectorySharedAction.Close -> finish()
                     }
                 }
-                .disposeOnDestroy()
+                .launchIn(lifecycleScope)
 
         val args = intent?.getParcelableExtra<SpaceManageArgs>(Mavericks.KEY_ARG)
         if (isFirstCreation()) {
@@ -194,8 +191,6 @@ class SpaceManageActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
         }
     }
 
-    override fun create(initialState: SpaceManageViewState) = sharedViewModelFactory.create(initialState)
-
     override fun configure(toolbar: MaterialToolbar) {
         configureToolbar(toolbar)
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt
index 8e16784a6d..125686d200 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt
@@ -25,13 +25,13 @@ import android.view.ViewGroup
 import androidx.appcompat.view.ActionMode
 import androidx.appcompat.view.ActionMode.Callback
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import androidx.transition.TransitionManager
 import com.airbnb.epoxy.EpoxyVisibilityTracker
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.appcompat.queryTextChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
@@ -39,16 +39,16 @@ import im.vector.app.core.platform.OnBackPressed
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.core.utils.toast
 import im.vector.app.databinding.FragmentSpaceAddRoomsBinding
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.appcompat.queryTextChanges
 import javax.inject.Inject
 
 class SpaceManageRoomsFragment @Inject constructor(
-        private val viewModelFactory: SpaceManageRoomsViewModel.Factory,
         private val epoxyController: SpaceManageRoomsController
 ) : VectorBaseFragment<FragmentSpaceAddRoomsBinding>(),
-        SpaceManageRoomsViewModel.Factory,
         OnBackPressed,
         SpaceManageRoomsController.Listener,
         Callback {
@@ -74,11 +74,11 @@ class SpaceManageRoomsFragment @Inject constructor(
         epoxyVisibilityTracker.attach(views.roomList)
 
         views.publicRoomsFilter.queryTextChanges()
-                .debounce(200, TimeUnit.MILLISECONDS)
-                .subscribeBy {
+                .debounce(200)
+                .onEach {
                     viewModel.handle(SpaceManageRoomViewAction.UpdateFilter(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         viewModel.onEach(SpaceManageRoomViewState::actionState) { actionState ->
             when (actionState) {
@@ -107,8 +107,6 @@ class SpaceManageRoomsFragment @Inject constructor(
         super.onDestroyView()
     }
 
-    override fun create(initialState: SpaceManageRoomViewState) = viewModelFactory.create(initialState)
-
     override fun invalidate() = withState(viewModel) { state ->
         epoxyController.setData(state)
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt
index d36e62db13..a1dd26a936 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt
@@ -16,18 +16,16 @@
 
 package im.vector.app.features.spaces.manage
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.mvrx.runCatchingToAsync
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.session.coroutineScope
@@ -56,19 +54,11 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceManageRoomViewState): SpaceManageRoomsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceManageRoomsViewModel, SpaceManageRoomViewState> {
+        override fun create(initialState: SpaceManageRoomViewState): SpaceManageRoomsViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpaceManageRoomsViewModel, SpaceManageRoomViewState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpaceManageRoomViewState): SpaceManageRoomsViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceManageRoomsViewModel, SpaceManageRoomViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: SpaceManageRoomViewAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt
index 133054236e..bedd1873e8 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt
@@ -16,13 +16,12 @@
 
 package im.vector.app.features.spaces.manage
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import org.matrix.android.sdk.api.session.Session
@@ -33,19 +32,11 @@ class SpaceManageSharedViewModel @AssistedInject constructor(
 ) : VectorViewModel<SpaceManageViewState, SpaceManagedSharedAction, SpaceManagedSharedViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpaceManageViewState): SpaceManageSharedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpaceManageSharedViewModel, SpaceManageViewState> {
+        override fun create(initialState: SpaceManageViewState): SpaceManageSharedViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpaceManageSharedViewModel, SpaceManageViewState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpaceManageViewState): SpaceManageSharedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpaceManageSharedViewModel, SpaceManageViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: SpaceManagedSharedAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt
index 5e5eb50b87..a0ab055311 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt
@@ -24,6 +24,7 @@ import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
@@ -49,6 +50,8 @@ import im.vector.app.features.roomprofile.settings.RoomSettingsViewModel
 import im.vector.app.features.roomprofile.settings.RoomSettingsViewState
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleActivity
 import im.vector.app.features.roomprofile.settings.joinrule.RoomJoinRuleSharedActionViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.model.GuestAccess
 import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
 import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
@@ -59,11 +62,9 @@ import javax.inject.Inject
 class SpaceSettingsFragment @Inject constructor(
         private val epoxyController: SpaceSettingsController,
         private val colorProvider: ColorProvider,
-        val viewModelFactory: RoomSettingsViewModel.Factory,
         private val avatarRenderer: AvatarRenderer,
         private val drawableProvider: DrawableProvider
 ) : VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
-        RoomSettingsViewModel.Factory,
         SpaceSettingsController.Callback,
         GalleryOrCameraDialogHelper.Listener,
         OnBackPressed {
@@ -81,10 +82,6 @@ class SpaceSettingsFragment @Inject constructor(
 
     override fun getMenuRes() = R.menu.vector_room_settings
 
-    override fun create(initialState: RoomSettingsViewState): RoomSettingsViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         setupToolbar(views.roomSettingsToolbar)
@@ -148,11 +145,11 @@ class SpaceSettingsFragment @Inject constructor(
     private fun setupRoomJoinRuleSharedActionViewModel() {
         roomJoinRuleSharedActionViewModel = activityViewModelProvider.get(RoomJoinRuleSharedActionViewModel::class.java)
         roomJoinRuleSharedActionViewModel
-                .observe()
-                .subscribe { action ->
+                .stream()
+                .onEach { action ->
                     viewModel.handle(RoomSettingsAction.SetRoomJoinRule(action.roomJoinRule))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private var ignoreChanges = false
diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt
index 3b84a12bc1..a269273cd5 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt
@@ -21,7 +21,9 @@ import android.content.Intent
 import android.os.Bundle
 import androidx.core.view.isGone
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Mavericks
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.hideKeyboard
@@ -29,7 +31,10 @@ import im.vector.app.core.platform.GenericIdArgs
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleLoadingBinding
 import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
+@AndroidEntryPoint
 class SpacePeopleActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>() {
 
     override fun getBinding() = ActivitySimpleLoadingBinding.inflate(layoutInflater)
@@ -73,8 +78,8 @@ class SpacePeopleActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>() {
 
         sharedActionViewModel = viewModelProvider.get(SpacePeopleSharedActionViewModel::class.java)
         sharedActionViewModel
-                .observe()
-                .subscribe { sharedAction ->
+                .stream()
+                .onEach { sharedAction ->
                     when (sharedAction) {
                         SpacePeopleSharedAction.Dismiss             -> finish()
                         is SpacePeopleSharedAction.NavigateToRoom   -> navigateToRooms(sharedAction)
@@ -86,7 +91,7 @@ class SpacePeopleActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>() {
                             ShareSpaceBottomSheet.show(supportFragmentManager, sharedAction.spaceId)
                         }
                     }
-                }.disposeOnDestroy()
+                }.launchIn(lifecycleScope)
     }
 
     private fun navigateToRooms(action: SpacePeopleSharedAction.NavigateToRoom) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleFragment.kt
index e1629d5dc1..c5cfed6974 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleFragment.kt
@@ -20,13 +20,13 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.appcompat.queryTextChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
@@ -37,21 +37,18 @@ import im.vector.app.core.resources.DrawableProvider
 import im.vector.app.databinding.FragmentRecyclerviewWithSearchBinding
 import im.vector.app.features.roomprofile.members.RoomMemberListAction
 import im.vector.app.features.roomprofile.members.RoomMemberListViewModel
-import im.vector.app.features.roomprofile.members.RoomMemberListViewState
-import io.reactivex.rxkotlin.subscribeBy
+import kotlinx.coroutines.flow.debounce
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.appcompat.queryTextChanges
 import javax.inject.Inject
 
 class SpacePeopleFragment @Inject constructor(
-        private val viewModelFactory: SpacePeopleViewModel.Factory,
-        private val roomMemberModelFactory: RoomMemberListViewModel.Factory,
         private val drawableProvider: DrawableProvider,
         private val colorProvider: ColorProvider,
         private val epoxyController: SpacePeopleListController
 ) : VectorBaseFragment<FragmentRecyclerviewWithSearchBinding>(),
-        SpacePeopleViewModel.Factory,
-        RoomMemberListViewModel.Factory,
         OnBackPressed, SpacePeopleListController.InteractionListener {
 
     private val viewModel by fragmentViewModel(SpacePeopleViewModel::class)
@@ -66,14 +63,6 @@ class SpacePeopleFragment @Inject constructor(
         return true
     }
 
-    override fun create(initialState: SpacePeopleViewState): SpacePeopleViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
-    override fun create(initialState: RoomMemberListViewState): RoomMemberListViewModel {
-        return roomMemberModelFactory.create(initialState)
-    }
-
     override fun invalidate() = withState(membersViewModel) { memberListState ->
         views.appBarTitle.text = getString(R.string.bottom_action_people)
         val memberCount = (memberListState.roomSummary.invoke()?.otherMemberIds?.size ?: 0) + 1
@@ -104,7 +93,7 @@ class SpacePeopleFragment @Inject constructor(
             handleViewEvents(it)
         }
 
-        viewModel.subscribe(this) {
+        viewModel.onEach {
             when (it.createAndInviteState) {
                 is Loading -> sharedActionViewModel.post(SpacePeopleSharedAction.ShowModalLoading)
                 Uninitialized,
@@ -130,11 +119,11 @@ class SpacePeopleFragment @Inject constructor(
     private fun setupSearchView() {
         views.memberNameFilter.queryHint = getString(R.string.search_members_hint)
         views.memberNameFilter.queryTextChanges()
-                .debounce(100, TimeUnit.MILLISECONDS)
-                .subscribeBy {
+                .debounce(100)
+                .onEach {
                     membersViewModel.handle(RoomMemberListAction.FilterMemberList(it.toString()))
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
     }
 
     private fun handleViewEvents(events: SpacePeopleViewEvents) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt
index efa7d97e9c..55d1dbe61e 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt
@@ -16,17 +16,15 @@
 
 package im.vector.app.features.spaces.people
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.raw.wellknown.getElementWellknown
@@ -44,19 +42,11 @@ class SpacePeopleViewModel @AssistedInject constructor(
 ) : VectorViewModel<SpacePeopleViewState, SpacePeopleViewAction, SpacePeopleViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpacePeopleViewState): SpacePeopleViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpacePeopleViewModel, SpacePeopleViewState> {
+        override fun create(initialState: SpacePeopleViewState): SpacePeopleViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpacePeopleViewModel, SpacePeopleViewState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpacePeopleViewState): SpacePeopleViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpacePeopleViewModel, SpacePeopleViewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: SpacePeopleViewAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewFragment.kt
index eb02ed7c2d..4d0d301721 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewFragment.kt
@@ -22,25 +22,27 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
-import com.jakewharton.rxbinding3.appcompat.navigationClicks
 import im.vector.app.R
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.flow.throttleFirst
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentSpacePreviewBinding
 import im.vector.app.features.home.AvatarRenderer
 import im.vector.app.features.spaces.SpacePreviewSharedAction
 import im.vector.app.features.spaces.SpacePreviewSharedActionViewModel
-import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.util.MatrixItem
-import java.util.concurrent.TimeUnit
+import reactivecircus.flowbinding.appcompat.navigationClicks
 import javax.inject.Inject
 
 @Parcelize
@@ -49,10 +51,9 @@ data class SpacePreviewArgs(
 ) : Parcelable
 
 class SpacePreviewFragment @Inject constructor(
-        private val viewModelFactory: SpacePreviewViewModel.Factory,
         private val avatarRenderer: AvatarRenderer,
         private val epoxyController: SpacePreviewController
-) : VectorBaseFragment<FragmentSpacePreviewBinding>(), SpacePreviewViewModel.Factory {
+) : VectorBaseFragment<FragmentSpacePreviewBinding>() {
 
     private val viewModel by fragmentViewModel(SpacePreviewViewModel::class)
     lateinit var sharedActionViewModel: SpacePreviewSharedActionViewModel
@@ -66,8 +67,6 @@ class SpacePreviewFragment @Inject constructor(
         sharedActionViewModel = activityViewModelProvider.get(SpacePreviewSharedActionViewModel::class.java)
     }
 
-    override fun create(initialState: SpacePreviewState) = viewModelFactory.create(initialState)
-
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
@@ -75,11 +74,11 @@ class SpacePreviewFragment @Inject constructor(
             handleViewEvents(it)
         }
 
-        views.roomPreviewNoPreviewToolbar.navigationClicks()
-                .throttleFirst(300, TimeUnit.MILLISECONDS)
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe { sharedActionViewModel.post(SpacePreviewSharedAction.DismissAction) }
-                .disposeOnDestroyView()
+        views.roomPreviewNoPreviewToolbar
+                .navigationClicks()
+                .throttleFirst(300)
+                .onEach { sharedActionViewModel.post(SpacePreviewSharedAction.DismissAction) }
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.spacePreviewRecyclerView.configureWith(epoxyController)
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt
index d71a4bef46..8d34ad94d8 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt
@@ -17,17 +17,16 @@
 package im.vector.app.features.spaces.preview
 
 import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.Dispatchers
@@ -58,19 +57,11 @@ class SpacePreviewViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SpacePreviewState): SpacePreviewViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SpacePreviewViewModel, SpacePreviewState> {
+        override fun create(initialState: SpacePreviewState): SpacePreviewViewModel
     }
 
-    companion object : MavericksViewModelFactory<SpacePreviewViewModel, SpacePreviewState> {
-        override fun create(viewModelContext: ViewModelContext, state: SpacePreviewState): SpacePreviewViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SpacePreviewViewModel, SpacePreviewState> by hiltMavericksViewModelFactory()
 
     override fun handle(action: SpacePreviewViewAction) {
         when (action) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceBottomSheet.kt
index bd69de0d95..6a98aa3cf8 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceBottomSheet.kt
@@ -25,17 +25,17 @@ import androidx.core.view.isVisible
 import androidx.fragment.app.FragmentManager
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.core.utils.startSharePlainTextIntent
 import im.vector.app.databinding.BottomSheetSpaceInviteBinding
 import im.vector.app.features.invite.InviteUsersToRoomActivity
 import kotlinx.parcelize.Parcelize
-import javax.inject.Inject
 
-class ShareSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceInviteBinding>(), ShareSpaceViewModel.Factory {
+@AndroidEntryPoint
+class ShareSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceInviteBinding>() {
 
     @Parcelize
     data class Args(
@@ -47,14 +47,6 @@ class ShareSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpa
 
     private val viewModel: ShareSpaceViewModel by fragmentViewModel(ShareSpaceViewModel::class)
 
-    @Inject lateinit var viewModelFactory: ShareSpaceViewModel.Factory
-
-    override fun create(initialState: ShareSpaceViewState): ShareSpaceViewModel = viewModelFactory.create(initialState)
-
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetSpaceInviteBinding {
         return BottomSheetSpaceInviteBinding.inflate(inflater, container, false)
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt
index d96cecbfbb..c624f1ed46 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt
@@ -16,15 +16,14 @@
 
 package im.vector.app.features.spaces.share
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
 import kotlinx.coroutines.flow.launchIn
@@ -38,19 +37,11 @@ class ShareSpaceViewModel @AssistedInject constructor(
         private val session: Session) : VectorViewModel<ShareSpaceViewState, ShareSpaceAction, ShareSpaceViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ShareSpaceViewState): ShareSpaceViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ShareSpaceViewModel, ShareSpaceViewState> {
+        override fun create(initialState: ShareSpaceViewState): ShareSpaceViewModel
     }
 
-    companion object : MavericksViewModelFactory<ShareSpaceViewModel, ShareSpaceViewState> {
-        override fun create(viewModelContext: ViewModelContext, state: ShareSpaceViewState): ShareSpaceViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<ShareSpaceViewModel, ShareSpaceViewState> by hiltMavericksViewModelFactory()
 
     init {
         val roomSummary = session.getRoomSummary(initialState.spaceId)
diff --git a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt
index 02f25563b8..0efb6119af 100644
--- a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt
@@ -20,8 +20,8 @@ import android.content.Context
 import android.content.Intent
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.replaceFragment
@@ -29,18 +29,13 @@ import im.vector.app.core.platform.SimpleFragmentActivity
 import org.matrix.android.sdk.api.session.terms.TermsService
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class ReviewTermsActivity : SimpleFragmentActivity() {
 
     @Inject lateinit var errorFormatter: ErrorFormatter
-    @Inject lateinit var viewModelFactory: ReviewTermsViewModel.Factory
 
     private val reviewTermsViewModel: ReviewTermsViewModel by viewModel()
 
-    override fun injectWith(injector: ScreenComponent) {
-        super.injectWith(injector)
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         super.initUiAndData()
 
diff --git a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt
index 6a46061a31..9932efb11a 100644
--- a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt
@@ -15,16 +15,15 @@
  */
 package im.vector.app.features.terms
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.launch
@@ -37,18 +36,11 @@ class ReviewTermsViewModel @AssistedInject constructor(
 ) : VectorViewModel<ReviewTermsViewState, ReviewTermsAction, ReviewTermsViewEvents>(initialState) {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ReviewTermsViewState): ReviewTermsViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ReviewTermsViewModel, ReviewTermsViewState> {
+        override fun create(initialState: ReviewTermsViewState): ReviewTermsViewModel
     }
 
-    companion object : MavericksViewModelFactory<ReviewTermsViewModel, ReviewTermsViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: ReviewTermsViewState): ReviewTermsViewModel? {
-            val activity: ReviewTermsActivity = (viewModelContext as ActivityViewModelContext).activity()
-            return activity.viewModelFactory.create(state)
-        }
-    }
+    companion object : MavericksViewModelFactory<ReviewTermsViewModel, ReviewTermsViewState> by hiltMavericksViewModelFactory()
 
     lateinit var termsArgs: ServiceTermsArgs
 
diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt
index db1bc3056a..7fa7a45131 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt
@@ -28,8 +28,8 @@ import androidx.fragment.app.FragmentManager
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorBaseActivity
@@ -37,15 +37,12 @@ import im.vector.app.core.utils.onPermissionDeniedSnackbar
 import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.matrixto.MatrixToBottomSheet
 import kotlinx.parcelize.Parcelize
-import javax.inject.Inject
 import kotlin.reflect.KClass
 
+@AndroidEntryPoint
 class UserCodeActivity : VectorBaseActivity<ActivitySimpleBinding>(),
-        UserCodeSharedViewModel.Factory,
         MatrixToBottomSheet.InteractionListener {
 
-    @Inject lateinit var viewModelFactory: UserCodeSharedViewModel.Factory
-
     val sharedViewModel: UserCodeSharedViewModel by viewModel()
 
     @Parcelize
@@ -57,10 +54,6 @@ class UserCodeActivity : VectorBaseActivity<ActivitySimpleBinding>(),
 
     override fun getCoordinatorLayout() = views.coordinatorLayout
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
         override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
             if (f is MatrixToBottomSheet) {
@@ -147,9 +140,6 @@ class UserCodeActivity : VectorBaseActivity<ActivitySimpleBinding>(),
         }.exhaustive
     }
 
-    override fun create(initialState: UserCodeState) =
-            viewModelFactory.create(initialState)
-
     companion object {
         fun newIntent(context: Context, userId: String): Intent {
             return Intent(context, UserCodeActivity::class.java).apply {
diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt
index 2319eef6c4..64bcf9cead 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt
@@ -16,15 +16,13 @@
 
 package im.vector.app.features.usercode
 
-import androidx.lifecycle.viewModelScope
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.createdirect.DirectRoomHelper
@@ -45,15 +43,7 @@ class UserCodeSharedViewModel @AssistedInject constructor(
         private val directRoomHelper: DirectRoomHelper,
         private val rawService: RawService) : VectorViewModel<UserCodeState, UserCodeActions, UserCodeShareViewEvents>(initialState) {
 
-    companion object : MavericksViewModelFactory<UserCodeSharedViewModel, UserCodeState> {
-        override fun create(viewModelContext: ViewModelContext, state: UserCodeState): UserCodeSharedViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<UserCodeSharedViewModel, UserCodeState> by hiltMavericksViewModelFactory()
 
     init {
         val user = session.getUser(initialState.userId)
@@ -66,8 +56,8 @@ class UserCodeSharedViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: UserCodeState): UserCodeSharedViewModel
+    interface Factory : MavericksAssistedViewModelFactory<UserCodeSharedViewModel, UserCodeState> {
+        override fun create(initialState: UserCodeState): UserCodeSharedViewModel
     }
 
     override fun handle(action: UserCodeActions) {
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt
index 83829c1119..86de26ac23 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListAction.kt
@@ -25,4 +25,5 @@ sealed class UserListAction : VectorViewModelAction {
     data class RemovePendingSelection(val pendingSelection: PendingSelection) : UserListAction()
     object ComputeMatrixToLinkForSharing : UserListAction()
     data class UpdateUserConsent(val consent: Boolean) : UserListAction()
+    object Resumed : UserListAction()
 }
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt
index 147367c1da..2028e59073 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListController.kt
@@ -146,7 +146,7 @@ class UserListController @Inject constructor(private val session: Session,
                             text(
                                     span {
                                         span {
-                                            text = host.stringProvider.getString(R.string.settings_discovery_consent_notice_off)
+                                            text = host.stringProvider.getString(R.string.settings_discovery_consent_notice_off_2)
                                         }
                                         +"\n"
                                         span {
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt
index daf5d73e8f..2b4d4f6f1e 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt
@@ -31,7 +31,6 @@ import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.chip.Chip
-import com.jakewharton.rxbinding3.widget.textChanges
 import im.vector.app.R
 import im.vector.app.core.extensions.cleanup
 import im.vector.app.core.extensions.configureWith
@@ -45,14 +44,17 @@ import im.vector.app.databinding.FragmentUserListBinding
 import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
 import im.vector.app.features.navigation.SettingsActivityPayload
 import im.vector.app.features.settings.VectorSettingsActivity
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
 import org.matrix.android.sdk.api.session.identity.ThreePid
 import org.matrix.android.sdk.api.session.user.model.User
+import reactivecircus.flowbinding.android.widget.textChanges
 import javax.inject.Inject
 
 class UserListFragment @Inject constructor(
         private val userListController: UserListController,
         private val dimensionConverter: DimensionConverter,
-        val homeServerCapabilitiesViewModelFactory: HomeServerCapabilitiesViewModel.Factory
 ) : VectorBaseFragment<FragmentUserListBinding>(),
         UserListController.Callback {
 
@@ -134,8 +136,8 @@ class UserListFragment @Inject constructor(
     private fun setupSearchView() {
         views.userListSearch
                 .textChanges()
-                .startWith(views.userListSearch.text)
-                .subscribe { text ->
+                .onStart { emit(views.userListSearch.text) }
+                .onEach { text ->
                     val searchValue = text.trim()
                     val action = if (searchValue.isBlank()) {
                         UserListAction.ClearSearchUsers
@@ -144,7 +146,7 @@ class UserListFragment @Inject constructor(
                     }
                     viewModel.handle(action)
                 }
-                .disposeOnDestroyView()
+                .launchIn(viewLifecycleOwner.lifecycleScope)
 
         views.userListSearch.setupAsSearch()
         views.userListSearch.requestFocus()
@@ -223,6 +225,11 @@ class UserListFragment @Inject constructor(
         )
     }
 
+    override fun onResume() {
+        super.onResume()
+        viewModel.handle(UserListAction.Resumed)
+    }
+
     override fun giveIdentityServerConsent() {
         withState(viewModel) { state ->
             requireContext().showIdentityServerConsentDialog(
diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt
index 457f8cbd9a..0ef56084b7 100644
--- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt
@@ -17,30 +17,29 @@
 package im.vector.app.features.userdirectory
 
 import androidx.lifecycle.asFlow
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
+import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.isEmail
 import im.vector.app.core.extensions.toggle
 import im.vector.app.core.platform.VectorViewModel
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.sample
 import org.matrix.android.sdk.api.MatrixPatterns
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.identity.IdentityServiceError
 import org.matrix.android.sdk.api.session.identity.IdentityServiceListener
 import org.matrix.android.sdk.api.session.identity.ThreePid
 import org.matrix.android.sdk.api.session.profile.ProfileService
@@ -58,28 +57,19 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
 
     private val knownUsersSearch = MutableStateFlow("")
     private val directoryUsersSearch = MutableStateFlow("")
-    private val identityServerUsersSearch = MutableStateFlow("")
+    private val identityServerUsersSearch = MutableStateFlow(UserSearch(searchTerm = ""))
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: UserListViewState): UserListViewModel
+    interface Factory : MavericksAssistedViewModelFactory<UserListViewModel, UserListViewState> {
+        override fun create(initialState: UserListViewState): UserListViewModel
     }
 
-    companion object : MavericksViewModelFactory<UserListViewModel, UserListViewState> {
-
-        override fun create(viewModelContext: ViewModelContext, state: UserListViewState): UserListViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<UserListViewModel, UserListViewState> by hiltMavericksViewModelFactory()
 
     private val identityServerListener = object : IdentityServiceListener {
         override fun onIdentityServerChange() {
             withState {
-                identityServerUsersSearch.tryEmit(it.searchTerm)
+                identityServerUsersSearch.tryEmit(UserSearch(it.searchTerm))
                 val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl())
                 setState {
                     copy(configuredIdentityServer = identityServerURL)
@@ -115,16 +105,29 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
             is UserListAction.RemovePendingSelection     -> handleRemoveSelectedUser(action)
             UserListAction.ComputeMatrixToLinkForSharing -> handleShareMyMatrixToLink()
             is UserListAction.UpdateUserConsent          -> handleISUpdateConsent(action)
+            UserListAction.Resumed                       -> handleResumed()
         }.exhaustive
     }
 
     private fun handleISUpdateConsent(action: UserListAction.UpdateUserConsent) {
         session.identityService().setUserConsent(action.consent)
         withState {
-            identityServerUsersSearch.tryEmit(it.searchTerm)
+            retryUserSearch(it)
         }
     }
 
+    private fun handleResumed() {
+        withState {
+            if (it.hasNoIdentityServerConfigured()) {
+                retryUserSearch(it)
+            }
+        }
+    }
+
+    private fun retryUserSearch(state: UserListViewState) {
+        identityServerUsersSearch.tryEmit(UserSearch(state.searchTerm, cacheBuster = System.currentTimeMillis()))
+    }
+
     private fun handleSearchUsers(searchTerm: String) {
         setState {
             copy(
@@ -140,7 +143,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
                 )
             }
         }
-        identityServerUsersSearch.tryEmit(searchTerm)
+        identityServerUsersSearch.tryEmit(UserSearch(searchTerm))
         knownUsersSearch.tryEmit(searchTerm)
         directoryUsersSearch.tryEmit(searchTerm)
     }
@@ -154,7 +157,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
     private fun handleClearSearchUsers() {
         knownUsersSearch.tryEmit("")
         directoryUsersSearch.tryEmit("")
-        identityServerUsersSearch.tryEmit("")
+        identityServerUsersSearch.tryEmit(UserSearch(""))
         setState {
             copy(searchTerm = "")
         }
@@ -162,18 +165,18 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
 
     private fun observeUsers() = withState { state ->
         identityServerUsersSearch
-                .filter { it.isEmail() }
+                .filter { it.searchTerm.isEmail() }
                 .sample(300)
                 .onEach { search ->
-                    executeSearchEmail(search)
+                    executeSearchEmail(search.searchTerm)
                 }.launchIn(viewModelScope)
 
         knownUsersSearch
                 .sample(300)
-                .flowOn(Dispatchers.Main)
                 .flatMapLatest { search ->
                     session.getPagedUsersLive(search, state.excludedUserIds).asFlow()
-                }.execute {
+                }
+                .execute {
                     copy(knownUsers = it)
                 }
 
@@ -187,11 +190,9 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
     private suspend fun executeSearchEmail(search: String) {
         suspend {
             val params = listOf(ThreePid.Email(search))
-            val foundThreePid = tryOrNull {
-                session.identityService().lookUp(params).firstOrNull()
-            }
+            val foundThreePid = session.identityService().lookUp(params).firstOrNull()
             if (foundThreePid == null) {
-                null
+                ThreePidUser(email = search, user = null)
             } else {
                 try {
                     val json = session.getProfile(foundThreePid.matrixId)
@@ -251,3 +252,10 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User
         setState { copy(pendingSelections = selections) }
     }
 }
+
+private fun UserListViewState.hasNoIdentityServerConfigured() = matchingEmail is Fail && matchingEmail.error == IdentityServiceError.NoIdentityServerConfigured
+
+/**
+ * Wrapper class to allow identical search terms to be re-emitted
+ */
+private data class UserSearch(val searchTerm: String, val cacheBuster: Long = 0)
diff --git a/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt b/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt
index 8a0f829f94..1a91c00e11 100644
--- a/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt
+++ b/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt
@@ -23,25 +23,23 @@ import java.io.File
 import java.io.FileOutputStream
 
 abstract class AbstractVoiceRecorder(
-        context: Context,
+        private val context: Context,
         private val filenameExt: String
 ) : VoiceRecorder {
-    private val outputDirectory = File(context.cacheDir, "voice_records")
+    private val outputDirectory: File by lazy {
+        File(context.cacheDir, "voice_records").also {
+            it.mkdirs()
+        }
+    }
 
     private var mediaRecorder: MediaRecorder? = null
     private var outputFile: File? = null
 
-    init {
-        if (!outputDirectory.exists()) {
-            outputDirectory.mkdirs()
-        }
-    }
-
     abstract fun setOutputFormat(mediaRecorder: MediaRecorder)
     abstract fun convertFile(recordedFile: File?): File?
 
     private fun init() {
-        MediaRecorder().let {
+        createMediaRecorder().let {
             it.setAudioSource(MediaRecorder.AudioSource.DEFAULT)
             setOutputFormat(it)
             it.setAudioEncodingBitRate(24000)
@@ -50,6 +48,15 @@ abstract class AbstractVoiceRecorder(
         }
     }
 
+    private fun createMediaRecorder(): MediaRecorder {
+        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            MediaRecorder(context)
+        } else {
+            @Suppress("DEPRECATION")
+            MediaRecorder()
+        }
+    }
+
     override fun startRecord() {
         init()
         outputFile = File(outputDirectory, "Voice message.$filenameExt")
diff --git a/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt b/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt
index f1b316c456..d2f7927d75 100644
--- a/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt
+++ b/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt
@@ -27,11 +27,9 @@ import javax.inject.Inject
 class VoicePlayerHelper @Inject constructor(
         context: Context
 ) {
-    private val outputDirectory = File(context.cacheDir, "voice_records")
-
-    init {
-        if (!outputDirectory.exists()) {
-            outputDirectory.mkdirs()
+    private val outputDirectory: File by lazy {
+        File(context.cacheDir, "voice_records").also {
+            it.mkdirs()
         }
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt b/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt
index ab8af20063..ab7913a99c 100644
--- a/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt
@@ -20,8 +20,8 @@ import android.content.Context
 import android.content.Intent
 import android.webkit.WebChromeClient
 import android.webkit.WebView
-import androidx.annotation.CallSuper
-import im.vector.app.core.di.ScreenComponent
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivityVectorWebViewBinding
 import org.matrix.android.sdk.api.session.Session
@@ -33,15 +33,14 @@ import javax.inject.Inject
  * It relies on the VectorWebViewClient
  * This class shouldn't be extended. To add new behaviors, you might create a new WebViewMode and a new WebViewEventListener
  */
+@AndroidEntryPoint
 class VectorWebViewActivity : VectorBaseActivity<ActivityVectorWebViewBinding>() {
 
     override fun getBinding() = ActivityVectorWebViewBinding.inflate(layoutInflater)
 
-    @Inject lateinit var session: Session
-
-    @CallSuper
-    override fun injectWith(injector: ScreenComponent) {
-        session = injector.activeSessionHolder().getActiveSession()
+    @Inject lateinit var activeSessionHolder: ActiveSessionHolder
+    val session: Session by lazy {
+        activeSessionHolder.getActiveSession()
     }
 
     override fun initUiAndData() {
diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt
index 23f1cfe119..a31edfcb02 100644
--- a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt
@@ -23,8 +23,8 @@ import androidx.core.view.isVisible
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.viewModel
 import com.google.android.material.appbar.MaterialToolbar
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
@@ -32,15 +32,12 @@ import im.vector.app.databinding.ActivityWidgetBinding
 import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
 import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewEvents
 import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewModel
-import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewState
 import org.matrix.android.sdk.api.session.events.model.Content
 import java.io.Serializable
-import javax.inject.Inject
 
+@AndroidEntryPoint
 class WidgetActivity : VectorBaseActivity<ActivityWidgetBinding>(),
-        ToolbarConfigurable,
-        WidgetViewModel.Factory,
-        RoomWidgetPermissionViewModel.Factory {
+        ToolbarConfigurable {
 
     companion object {
 
@@ -66,9 +63,6 @@ class WidgetActivity : VectorBaseActivity<ActivityWidgetBinding>(),
         }
     }
 
-    @Inject lateinit var viewModelFactory: WidgetViewModel.Factory
-    @Inject lateinit var permissionsViewModelFactory: RoomWidgetPermissionViewModel.Factory
-
     private val viewModel: WidgetViewModel by viewModel()
     private val permissionViewModel: RoomWidgetPermissionViewModel by viewModel()
 
@@ -78,10 +72,6 @@ class WidgetActivity : VectorBaseActivity<ActivityWidgetBinding>(),
 
     override fun getTitleRes() = R.string.room_widget_activity_title
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun initUiAndData() {
         val widgetArgs: WidgetArgs? = intent?.extras?.getParcelable(Mavericks.KEY_ARG)
         if (widgetArgs == null) {
@@ -133,14 +123,6 @@ class WidgetActivity : VectorBaseActivity<ActivityWidgetBinding>(),
         }
     }
 
-    override fun create(initialState: WidgetViewState): WidgetViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
-    override fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel {
-        return permissionsViewModelFactory.create(initialState)
-    }
-
     private fun handleClose(event: WidgetViewEvents.Close) {
         if (event.content != null) {
             val intent = createResultIntent(event.content)
diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt
index 1cf3e367ea..20fae6e31a 100644
--- a/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt
@@ -17,16 +17,15 @@
 package im.vector.app.features.widgets
 
 import android.net.Uri
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Fail
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.widgets.permissions.WidgetPermissionsHelper
@@ -57,21 +56,11 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
         IntegrationManagerService.Listener {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: WidgetViewState): WidgetViewModel
+    interface Factory : MavericksAssistedViewModelFactory<WidgetViewModel, WidgetViewState> {
+        override fun create(initialState: WidgetViewState): WidgetViewModel
     }
 
-    companion object : MavericksViewModelFactory<WidgetViewModel, WidgetViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: WidgetViewState): WidgetViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<WidgetViewModel, WidgetViewState> by hiltMavericksViewModelFactory()
 
     private val room = session.getRoom(initialState.roomId)
     private val widgetService = session.widgetService()
diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt
index e7ee2aed1f..ae3028925a 100644
--- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt
@@ -26,8 +26,8 @@ import android.view.ViewGroup
 import com.airbnb.mvrx.Mavericks
 import com.airbnb.mvrx.activityViewModel
 import com.airbnb.mvrx.withState
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.withArgs
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetRoomWidgetPermissionBinding
@@ -36,6 +36,7 @@ import im.vector.app.features.widgets.WidgetArgs
 import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
+@AndroidEntryPoint
 class RoomWidgetPermissionBottomSheet :
         VectorBaseBottomSheetDialogFragment<BottomSheetRoomWidgetPermissionBinding>() {
 
@@ -49,10 +50,6 @@ class RoomWidgetPermissionBottomSheet :
 
     override val showExpanded = true
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     // Use this if you don't need the full activity view model
     var directListener: ((Boolean) -> Unit)? = null
 
diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt
index 71eaebbc91..f29e6d1928 100644
--- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt
@@ -15,14 +15,13 @@
  */
 package im.vector.app.features.widgets.permissions
 
-import com.airbnb.mvrx.ActivityViewModelContext
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.R
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.VectorViewModel
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
@@ -141,19 +140,9 @@ class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val in
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel
+    interface Factory : MavericksAssistedViewModelFactory<RoomWidgetPermissionViewModel, RoomWidgetPermissionViewState> {
+        override fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel
     }
 
-    companion object : MavericksViewModelFactory<RoomWidgetPermissionViewModel, RoomWidgetPermissionViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<RoomWidgetPermissionViewModel, RoomWidgetPermissionViewState> by hiltMavericksViewModelFactory()
 }
diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt
index 92af25994a..8fb5b27376 100644
--- a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt
@@ -17,16 +17,15 @@
 package im.vector.app.features.workers.signout
 
 import androidx.lifecycle.MutableLiveData
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.platform.EmptyAction
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -68,21 +67,11 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
         VectorViewModel<ServerBackupStatusViewState, EmptyAction, EmptyViewEvents>(initialState), KeysBackupStateListener {
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel
+    interface Factory : MavericksAssistedViewModelFactory<ServerBackupStatusViewModel, ServerBackupStatusViewState> {
+        override fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel
     }
 
-    companion object : MavericksViewModelFactory<ServerBackupStatusViewModel, ServerBackupStatusViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: ServerBackupStatusViewState): ServerBackupStatusViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<ServerBackupStatusViewModel, ServerBackupStatusViewState> by hiltMavericksViewModelFactory()
 
     // Keys exported manually
     val keysExportedToFile = MutableLiveData<Boolean>()
diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt
index 7f089082a2..5d38dac15f 100644
--- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt
@@ -31,8 +31,8 @@ import com.airbnb.mvrx.withState
 import com.google.android.material.bottomsheet.BottomSheetBehavior
 import com.google.android.material.bottomsheet.BottomSheetDialog
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
-import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.dialogs.ExportKeysDialog
 import im.vector.app.core.extensions.queryExportKeys
 import im.vector.app.core.extensions.registerStartForActivityResult
@@ -42,12 +42,11 @@ import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
 import im.vector.app.features.crypto.recover.BootstrapBottomSheet
 import im.vector.app.features.crypto.recover.SetupMode
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
-import javax.inject.Inject
 
 // TODO this needs to be refactored to current standard and remove legacy
+@AndroidEntryPoint
 class SignOutBottomSheetDialogFragment :
-        VectorBaseBottomSheetDialogFragment<BottomSheetLogoutAndBackupBinding>(),
-        SignoutCheckViewModel.Factory {
+        VectorBaseBottomSheetDialogFragment<BottomSheetLogoutAndBackupBinding>() {
 
     var onSignOut: Runnable? = null
 
@@ -59,19 +58,8 @@ class SignOutBottomSheetDialogFragment :
         isCancelable = true
     }
 
-    @Inject
-    lateinit var viewModelFactory: SignoutCheckViewModel.Factory
-
-    override fun create(initialState: SignoutCheckViewState): SignoutCheckViewModel {
-        return viewModelFactory.create(initialState)
-    }
-
     private val viewModel: SignoutCheckViewModel by fragmentViewModel(SignoutCheckViewModel::class)
 
-    override fun injectWith(injector: ScreenComponent) {
-        injector.inject(this)
-    }
-
     override fun onResume() {
         super.onResume()
         viewModel.refreshRemoteStateIfNeeded()
diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutUiWorker.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutUiWorker.kt
index c5fa130d9b..59ea37036c 100644
--- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutUiWorker.kt
+++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutUiWorker.kt
@@ -20,14 +20,14 @@ import androidx.fragment.app.FragmentActivity
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import im.vector.app.R
 import im.vector.app.core.extensions.cannotLogoutSafely
-import im.vector.app.core.extensions.vectorComponent
+import im.vector.app.core.extensions.singletonEntryPoint
 import im.vector.app.features.MainActivity
 import im.vector.app.features.MainActivityArgs
 
 class SignOutUiWorker(private val activity: FragmentActivity) {
 
     fun perform() {
-        val session = activity.vectorComponent().activeSessionHolder().getSafeActiveSession() ?: return
+        val session = activity.singletonEntryPoint().activeSessionHolder().getSafeActiveSession() ?: return
         if (session.cannotLogoutSafely()) {
             // The backup check on logout flow has to be displayed if there are keys in the store, and the keys backup state is not Ready
             val signOutDialog = SignOutBottomSheetDialogFragment.newInstance()
diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt
index 057d9e31f8..4daaef6fe1 100644
--- a/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt
@@ -17,18 +17,17 @@
 package im.vector.app.features.workers.signout
 
 import android.net.Uri
-import com.airbnb.mvrx.ActivityViewModelContext
 import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MavericksState
 import com.airbnb.mvrx.MavericksViewModelFactory
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized
-import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
@@ -66,21 +65,11 @@ class SignoutCheckViewModel @AssistedInject constructor(
     }
 
     @AssistedFactory
-    interface Factory {
-        fun create(initialState: SignoutCheckViewState): SignoutCheckViewModel
+    interface Factory : MavericksAssistedViewModelFactory<SignoutCheckViewModel, SignoutCheckViewState> {
+        override fun create(initialState: SignoutCheckViewState): SignoutCheckViewModel
     }
 
-    companion object : MavericksViewModelFactory<SignoutCheckViewModel, SignoutCheckViewState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: SignoutCheckViewState): SignoutCheckViewModel? {
-            val factory = when (viewModelContext) {
-                is FragmentViewModelContext -> viewModelContext.fragment as? Factory
-                is ActivityViewModelContext -> viewModelContext.activity as? Factory
-            }
-            return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
-        }
-    }
+    companion object : MavericksViewModelFactory<SignoutCheckViewModel, SignoutCheckViewState> by hiltMavericksViewModelFactory()
 
     init {
         session.cryptoService().keysBackupService().addListener(this)
diff --git a/vector/src/main/res/drawable/ic_attachment_poll_white_24dp.xml b/vector/src/main/res/drawable/ic_attachment_poll_white_24dp.xml
new file mode 100644
index 0000000000..8cbcc6e47c
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_attachment_poll_white_24dp.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M10.5,2C10.2239,2 10,2.2239 10,2.5V22H14V2.5C14,2.2239 13.7761,2 13.5,2H10.5ZM3,9.5C3,9.2239 3.2239,9 3.5,9H6.5C6.7761,9 7,9.2239 7,9.5V22H3V9.5ZM17,13.5C17,13.2239 17.2239,13 17.5,13H20.5C20.7761,13 21,13.2239 21,13.5V22H17V13.5Z"
+      android:fillColor="#FFFFFF"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/vector/src/main/res/drawable/ic_delete_10dp.xml b/vector/src/main/res/drawable/ic_delete_10dp.xml
new file mode 100644
index 0000000000..f8229a71d0
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_delete_10dp.xml
@@ -0,0 +1,18 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="10dp"
+    android:height="10dp"
+    android:viewportWidth="10"
+    android:viewportHeight="10">
+  <path
+      android:pathData="M0.9998,0.9997L8.9998,8.9997"
+      android:strokeWidth="2"
+      android:fillColor="#00000000"
+      android:strokeColor="#737D8C"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M9.0005,0.9997L1.0005,8.9997"
+      android:strokeWidth="2"
+      android:fillColor="#00000000"
+      android:strokeColor="#737D8C"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/vector/src/main/res/layout/fragment_create_poll.xml b/vector/src/main/res/layout/fragment_create_poll.xml
new file mode 100644
index 0000000000..b82342558c
--- /dev/null
+++ b/vector/src/main/res/layout/fragment_create_poll.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/appBarLayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <com.google.android.material.appbar.MaterialToolbar
+            android:id="@+id/createPollToolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?actionBarSize"
+            app:contentInsetStart="0dp">
+
+            <androidx.constraintlayout.widget.ConstraintLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <ImageView
+                    android:id="@+id/createPollClose"
+                    android:layout_width="@dimen/layout_touch_size"
+                    android:layout_height="@dimen/layout_touch_size"
+                    android:clickable="true"
+                    android:contentDescription="@string/action_close"
+                    android:focusable="true"
+                    android:foreground="?attr/selectableItemBackground"
+                    android:scaleType="center"
+                    android:src="@drawable/ic_x_18dp"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintStart_toStartOf="parent"
+                    app:layout_constraintTop_toTopOf="parent"
+                    app:tint="?vctr_content_secondary"
+                    tools:ignore="MissingPrefix" />
+
+                <TextView
+                    android:id="@+id/createPollTitle"
+                    style="@style/Widget.Vector.TextView.HeadlineMedium"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="8dp"
+                    android:layout_marginEnd="8dp"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:text="@string/create_poll_title"
+                    android:textColor="?vctr_content_primary"
+                    android:textStyle="bold"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
+                    app:layout_constraintHorizontal_bias="0.0"
+                    app:layout_constraintStart_toEndOf="@+id/createPollClose"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+            </androidx.constraintlayout.widget.ConstraintLayout>
+
+        </com.google.android.material.appbar.MaterialToolbar>
+
+    </com.google.android.material.appbar.AppBarLayout>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/createPollRecyclerView"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:overScrollMode="always"
+        app:layout_behavior="@string/appbar_scrolling_view_behavior"
+        app:layout_constraintBottom_toTopOf="@id/createPollButton"
+        app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
+        tools:listitem="@layout/item_form_text_input_with_delete" />
+
+    <Button
+        android:id="@+id/createPollButton"
+        style="@style/Widget.Vector.Button.CallToAction"
+        android:layout_width="match_parent"
+        android:layout_height="56dp"
+        android:layout_margin="16dp"
+        android:text="@string/create_poll_button"
+        app:layout_constraintBottom_toBottomOf="parent"
+        tools:enabled="false" />
+
+    <TextView
+        android:id="@+id/createPollToast"
+        style="@style/Widget.Vector.TextView.Caption.Toast"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:layout_marginBottom="84dp"
+        android:accessibilityLiveRegion="polite"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        tools:text="@string/create_poll_empty_question_error"
+        tools:visibility="visible" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/vector/src/main/res/layout/item_form_text_input.xml b/vector/src/main/res/layout/item_form_text_input.xml
index adc599f314..9a8d035758 100644
--- a/vector/src/main/res/layout/item_form_text_input.xml
+++ b/vector/src/main/res/layout/item_form_text_input.xml
@@ -9,6 +9,7 @@
 
     <com.google.android.material.textfield.TextInputLayout
         android:id="@+id/formTextInputTextInputLayout"
+        style="@style/Widget.Vector.TextInputLayout.Form"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/layout_horizontal_margin"
diff --git a/vector/src/main/res/layout/item_form_text_input_with_delete.xml b/vector/src/main/res/layout/item_form_text_input_with_delete.xml
new file mode 100644
index 0000000000..ba19db4b46
--- /dev/null
+++ b/vector/src/main/res/layout/item_form_text_input_with_delete.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:colorBackground"
+    android:minHeight="@dimen/item_form_min_height">
+
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/formTextInputTextInputLayout"
+        style="@style/Widget.Vector.TextInputLayout.Form"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/layout_horizontal_margin"
+        android:layout_marginEnd="@dimen/layout_horizontal_margin"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/formTextInputDeleteButton"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/formTextInputTextInputEditText"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            tools:hint="@string/create_room_name_hint" />
+
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <ImageButton
+        android:id="@+id/formTextInputDeleteButton"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginEnd="@dimen/layout_horizontal_margin"
+        android:background="@drawable/circle"
+        android:contentDescription="@string/delete"
+        android:scaleType="center"
+        android:src="@drawable/ic_delete_10dp"
+        app:layout_constraintBottom_toBottomOf="@id/formTextInputTextInputLayout"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="@id/formTextInputTextInputLayout"
+        app:tint="?vctr_content_secondary" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/vector/src/main/res/layout/view_attachment_type_selector.xml b/vector/src/main/res/layout/view_attachment_type_selector.xml
index 648ca91820..bc747778a7 100644
--- a/vector/src/main/res/layout/view_attachment_type_selector.xml
+++ b/vector/src/main/res/layout/view_attachment_type_selector.xml
@@ -163,5 +163,36 @@
 
             </LinearLayout>
         </LinearLayout>
+
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="16dp"
+            android:baselineAligned="false"
+            android:orientation="horizontal"
+            android:visibility="gone"
+            android:weightSum="3">
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:orientation="vertical">
+
+                <ImageButton
+                    android:id="@+id/attachmentPollButton"
+                    style="@style/AttachmentTypeSelectorButton"
+                    android:contentDescription="@string/attachment_type_poll"
+                    android:src="@drawable/ic_attachment_poll_white_24dp"
+                    tools:background="?colorPrimary" />
+
+                <TextView
+                    style="@style/AttachmentTypeSelectorLabel"
+                    android:importantForAccessibility="no"
+                    android:text="@string/attachment_type_poll" />
+            </LinearLayout>
+        </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/vector/src/main/res/menu/menu_devtools.xml b/vector/src/main/res/menu/menu_devtools.xml
index d6f97292d6..dcef953d8f 100644
--- a/vector/src/main/res/menu/menu_devtools.xml
+++ b/vector/src/main/res/menu/menu_devtools.xml
@@ -9,6 +9,7 @@
         tools:visible="true"
         app:showAsAction="ifRoom"
         android:icon="@drawable/ic_edit"
+        app:iconTint="?vctr_content_secondary"
         android:title="@string/edit" />
 
     <item
@@ -17,6 +18,7 @@
         tools:visible="true"
         app:showAsAction="ifRoom"
         android:icon="@drawable/ic_send"
+        app:iconTint="?vctr_content_secondary"
         android:title="@string/send" />
 
 </menu>
\ No newline at end of file
diff --git a/vector/src/main/res/raw/emoji_picker_datasource.json b/vector/src/main/res/raw/emoji_picker_datasource.json
index 8843e7759a..80131cefac 100644
--- a/vector/src/main/res/raw/emoji_picker_datasource.json
+++ b/vector/src/main/res/raw/emoji_picker_datasource.json
@@ -1 +1 @@
-{"compressed":true,"categories":[{"id":"smileys_&_emotion","name":"Smileys & Emotion","emojis":["grinning-face","grinning-face-with-big-eyes","grinning-face-with-smiling-eyes","beaming-face-with-smiling-eyes","grinning-squinting-face","grinning-face-with-sweat","rolling-on-the-floor-laughing","face-with-tears-of-joy","slightly-smiling-face","upsidedown-face","melting-face","winking-face","smiling-face-with-smiling-eyes","smiling-face-with-halo","smiling-face-with-hearts","smiling-face-with-hearteyes","starstruck","face-blowing-a-kiss","kissing-face","smiling-face","kissing-face-with-closed-eyes","kissing-face-with-smiling-eyes","smiling-face-with-tear","face-savoring-food","face-with-tongue","winking-face-with-tongue","zany-face","squinting-face-with-tongue","moneymouth-face","smiling-face-with-open-hands","face-with-hand-over-mouth","face-with-open-eyes-and-hand-over-mouth","face-with-peeking-eye","shushing-face","thinking-face","saluting-face","zippermouth-face","face-with-raised-eyebrow","neutral-face","expressionless-face","face-without-mouth","dotted-line-face","face-in-clouds","smirking-face","unamused-face","face-with-rolling-eyes","grimacing-face","face-exhaling","lying-face","relieved-face","pensive-face","sleepy-face","drooling-face","sleeping-face","face-with-medical-mask","face-with-thermometer","face-with-headbandage","nauseated-face","face-vomiting","sneezing-face","hot-face","cold-face","woozy-face","face-with-crossedout-eyes","face-with-spiral-eyes","exploding-head","cowboy-hat-face","partying-face","disguised-face","smiling-face-with-sunglasses","nerd-face","face-with-monocle","confused-face","face-with-diagonal-mouth","worried-face","slightly-frowning-face","frowning-face","face-with-open-mouth","hushed-face","astonished-face","flushed-face","pleading-face","face-holding-back-tears","frowning-face-with-open-mouth","anguished-face","fearful-face","anxious-face-with-sweat","sad-but-relieved-face","crying-face","loudly-crying-face","face-screaming-in-fear","confounded-face","persevering-face","disappointed-face","downcast-face-with-sweat","weary-face","tired-face","yawning-face","face-with-steam-from-nose","pouting-face","angry-face","face-with-symbols-on-mouth","smiling-face-with-horns","angry-face-with-horns","skull","skull-and-crossbones","pile-of-poo","clown-face","ogre","goblin","ghost","alien","alien-monster","robot","grinning-cat","grinning-cat-with-smiling-eyes","cat-with-tears-of-joy","smiling-cat-with-hearteyes","cat-with-wry-smile","kissing-cat","weary-cat","crying-cat","pouting-cat","seenoevil-monkey","hearnoevil-monkey","speaknoevil-monkey","kiss-mark","love-letter","heart-with-arrow","heart-with-ribbon","sparkling-heart","growing-heart","beating-heart","revolving-hearts","two-hearts","heart-decoration","heart-exclamation","broken-heart","heart-on-fire","mending-heart","red-heart","orange-heart","yellow-heart","green-heart","blue-heart","purple-heart","brown-heart","black-heart","white-heart","hundred-points","anger-symbol","collision","dizzy","sweat-droplets","dashing-away","hole","bomb","speech-balloon","eye-in-speech-bubble","left-speech-bubble","right-anger-bubble","thought-balloon","zzz"]},{"id":"people_&_body","name":"People & Body","emojis":["waving-hand","raised-back-of-hand","hand-with-fingers-splayed","raised-hand","vulcan-salute","rightwards-hand","leftwards-hand","palm-down-hand","palm-up-hand","ok-hand","pinched-fingers","pinching-hand","victory-hand","crossed-fingers","hand-with-index-finger-and-thumb-crossed","loveyou-gesture","sign-of-the-horns","call-me-hand","backhand-index-pointing-left","backhand-index-pointing-right","backhand-index-pointing-up","middle-finger","backhand-index-pointing-down","index-pointing-up","index-pointing-at-the-viewer","thumbs-up","thumbs-down","raised-fist","oncoming-fist","leftfacing-fist","rightfacing-fist","clapping-hands","raising-hands","heart-hands","open-hands","palms-up-together","handshake","folded-hands","writing-hand","nail-polish","selfie","flexed-biceps","mechanical-arm","mechanical-leg","leg","foot","ear","ear-with-hearing-aid","nose","brain","anatomical-heart","lungs","tooth","bone","eyes","eye","tongue","mouth","biting-lip","baby","child","boy","girl","person","person-blond-hair","man","person-beard","man-beard","woman-beard","man-red-hair","man-curly-hair","man-white-hair","man-bald","woman","woman-red-hair","person-red-hair","woman-curly-hair","person-curly-hair","woman-white-hair","person-white-hair","woman-bald","person-bald","woman-blond-hair","man-blond-hair","older-person","old-man","old-woman","person-frowning","man-frowning","woman-frowning","person-pouting","man-pouting","woman-pouting","person-gesturing-no","man-gesturing-no","woman-gesturing-no","person-gesturing-ok","man-gesturing-ok","woman-gesturing-ok","person-tipping-hand","man-tipping-hand","woman-tipping-hand","person-raising-hand","man-raising-hand","woman-raising-hand","deaf-person","deaf-man","deaf-woman","person-bowing","man-bowing","woman-bowing","person-facepalming","man-facepalming","woman-facepalming","person-shrugging","man-shrugging","woman-shrugging","health-worker","man-health-worker","woman-health-worker","student","man-student","woman-student","teacher","man-teacher","woman-teacher","judge","man-judge","woman-judge","farmer","man-farmer","woman-farmer","cook","man-cook","woman-cook","mechanic","man-mechanic","woman-mechanic","factory-worker","man-factory-worker","woman-factory-worker","office-worker","man-office-worker","woman-office-worker","scientist","man-scientist","woman-scientist","technologist","man-technologist","woman-technologist","singer","man-singer","woman-singer","artist","man-artist","woman-artist","pilot","man-pilot","woman-pilot","astronaut","man-astronaut","woman-astronaut","firefighter","man-firefighter","woman-firefighter","police-officer","man-police-officer","woman-police-officer","detective","man-detective","woman-detective","guard","man-guard","woman-guard","ninja","construction-worker","man-construction-worker","woman-construction-worker","person-with-crown","prince","princess","person-wearing-turban","man-wearing-turban","woman-wearing-turban","person-with-skullcap","woman-with-headscarf","person-in-tuxedo","man-in-tuxedo","woman-in-tuxedo","person-with-veil","man-with-veil","woman-with-veil","pregnant-woman","pregnant-man","pregnant-person","breastfeeding","woman-feeding-baby","man-feeding-baby","person-feeding-baby","baby-angel","santa-claus","mrs-claus","mx-claus","superhero","man-superhero","woman-superhero","supervillain","man-supervillain","woman-supervillain","mage","man-mage","woman-mage","fairy","man-fairy","woman-fairy","vampire","man-vampire","woman-vampire","merperson","merman","mermaid","elf","man-elf","woman-elf","genie","man-genie","woman-genie","zombie","man-zombie","woman-zombie","troll","person-getting-massage","man-getting-massage","woman-getting-massage","person-getting-haircut","man-getting-haircut","woman-getting-haircut","person-walking","man-walking","woman-walking","person-standing","man-standing","woman-standing","person-kneeling","man-kneeling","woman-kneeling","person-with-white-cane","man-with-white-cane","woman-with-white-cane","person-in-motorized-wheelchair","man-in-motorized-wheelchair","woman-in-motorized-wheelchair","person-in-manual-wheelchair","man-in-manual-wheelchair","woman-in-manual-wheelchair","person-running","man-running","woman-running","woman-dancing","man-dancing","person-in-suit-levitating","people-with-bunny-ears","men-with-bunny-ears","women-with-bunny-ears","person-in-steamy-room","man-in-steamy-room","woman-in-steamy-room","person-climbing","man-climbing","woman-climbing","person-fencing","horse-racing","skier","snowboarder","person-golfing","man-golfing","woman-golfing","person-surfing","man-surfing","woman-surfing","person-rowing-boat","man-rowing-boat","woman-rowing-boat","person-swimming","man-swimming","woman-swimming","person-bouncing-ball","man-bouncing-ball","woman-bouncing-ball","person-lifting-weights","man-lifting-weights","woman-lifting-weights","person-biking","man-biking","woman-biking","person-mountain-biking","man-mountain-biking","woman-mountain-biking","person-cartwheeling","man-cartwheeling","woman-cartwheeling","people-wrestling","men-wrestling","women-wrestling","person-playing-water-polo","man-playing-water-polo","woman-playing-water-polo","person-playing-handball","man-playing-handball","woman-playing-handball","person-juggling","man-juggling","woman-juggling","person-in-lotus-position","man-in-lotus-position","woman-in-lotus-position","person-taking-bath","person-in-bed","people-holding-hands","women-holding-hands","woman-and-man-holding-hands","men-holding-hands","kiss","kiss-woman-man","kiss-man-man","kiss-woman-woman","couple-with-heart","couple-with-heart-woman-man","couple-with-heart-man-man","couple-with-heart-woman-woman","family","family-man-woman-boy","family-man-woman-girl","family-man-woman-girl-boy","family-man-woman-boy-boy","family-man-woman-girl-girl","family-man-man-boy","family-man-man-girl","family-man-man-girl-boy","family-man-man-boy-boy","family-man-man-girl-girl","family-woman-woman-boy","family-woman-woman-girl","family-woman-woman-girl-boy","family-woman-woman-boy-boy","family-woman-woman-girl-girl","family-man-boy","family-man-boy-boy","family-man-girl","family-man-girl-boy","family-man-girl-girl","family-woman-boy","family-woman-boy-boy","family-woman-girl","family-woman-girl-boy","family-woman-girl-girl","speaking-head","bust-in-silhouette","busts-in-silhouette","people-hugging","footprints"]},{"id":"animals_&_nature","name":"Animals & Nature","emojis":["monkey-face","monkey","gorilla","orangutan","dog-face","dog","guide-dog","service-dog","poodle","wolf","fox","raccoon","cat-face","cat","black-cat","lion","tiger-face","tiger","leopard","horse-face","horse","unicorn","zebra","deer","bison","cow-face","ox","water-buffalo","cow","pig-face","pig","boar","pig-nose","ram","ewe","goat","camel","twohump-camel","llama","giraffe","elephant","mammoth","rhinoceros","hippopotamus","mouse-face","mouse","rat","hamster","rabbit-face","rabbit","chipmunk","beaver","hedgehog","bat","bear","polar-bear","koala","panda","sloth","otter","skunk","kangaroo","badger","paw-prints","turkey","chicken","rooster","hatching-chick","baby-chick","frontfacing-baby-chick","bird","penguin","dove","eagle","duck","swan","owl","dodo","feather","flamingo","peacock","parrot","frog","crocodile","turtle","lizard","snake","dragon-face","dragon","sauropod","trex","spouting-whale","whale","dolphin","seal","fish","tropical-fish","blowfish","shark","octopus","spiral-shell","coral","snail","butterfly","bug","ant","honeybee","beetle","lady-beetle","cricket","cockroach","spider","spider-web","scorpion","mosquito","fly","worm","microbe","bouquet","cherry-blossom","white-flower","lotus","rosette","rose","wilted-flower","hibiscus","sunflower","blossom","tulip","seedling","potted-plant","evergreen-tree","deciduous-tree","palm-tree","cactus","sheaf-of-rice","herb","shamrock","four-leaf-clover","maple-leaf","fallen-leaf","leaf-fluttering-in-wind","empty-nest","nest-with-eggs"]},{"id":"food_&_drink","name":"Food & Drink","emojis":["grapes","melon","watermelon","tangerine","lemon","banana","pineapple","mango","red-apple","green-apple","pear","peach","cherries","strawberry","blueberries","kiwi-fruit","tomato","olive","coconut","avocado","eggplant","potato","carrot","ear-of-corn","hot-pepper","bell-pepper","cucumber","leafy-green","broccoli","garlic","onion","mushroom","peanuts","beans","chestnut","bread","croissant","baguette-bread","flatbread","pretzel","bagel","pancakes","waffle","cheese-wedge","meat-on-bone","poultry-leg","cut-of-meat","bacon","hamburger","french-fries","pizza","hot-dog","sandwich","taco","burrito","tamale","stuffed-flatbread","falafel","egg","cooking","shallow-pan-of-food","pot-of-food","fondue","bowl-with-spoon","green-salad","popcorn","butter","salt","canned-food","bento-box","rice-cracker","rice-ball","cooked-rice","curry-rice","steaming-bowl","spaghetti","roasted-sweet-potato","oden","sushi","fried-shrimp","fish-cake-with-swirl","moon-cake","dango","dumpling","fortune-cookie","takeout-box","crab","lobster","shrimp","squid","oyster","soft-ice-cream","shaved-ice","ice-cream","doughnut","cookie","birthday-cake","shortcake","cupcake","pie","chocolate-bar","candy","lollipop","custard","honey-pot","baby-bottle","glass-of-milk","hot-beverage","teapot","teacup-without-handle","sake","bottle-with-popping-cork","wine-glass","cocktail-glass","tropical-drink","beer-mug","clinking-beer-mugs","clinking-glasses","tumbler-glass","pouring-liquid","cup-with-straw","bubble-tea","beverage-box","mate","ice","chopsticks","fork-and-knife-with-plate","fork-and-knife","spoon","kitchen-knife","jar","amphora"]},{"id":"travel_&_places","name":"Travel & Places","emojis":["globe-showing-europeafrica","globe-showing-americas","globe-showing-asiaaustralia","globe-with-meridians","world-map","map-of-japan","compass","snowcapped-mountain","mountain","volcano","mount-fuji","camping","beach-with-umbrella","desert","desert-island","national-park","stadium","classical-building","building-construction","brick","rock","wood","hut","houses","derelict-house","house","house-with-garden","office-building","japanese-post-office","post-office","hospital","bank","hotel","love-hotel","convenience-store","school","department-store","factory","japanese-castle","castle","wedding","tokyo-tower","statue-of-liberty","church","mosque","hindu-temple","synagogue","shinto-shrine","kaaba","fountain","tent","foggy","night-with-stars","cityscape","sunrise-over-mountains","sunrise","cityscape-at-dusk","sunset","bridge-at-night","hot-springs","carousel-horse","playground-slide","ferris-wheel","roller-coaster","barber-pole","circus-tent","locomotive","railway-car","highspeed-train","bullet-train","train","metro","light-rail","station","tram","monorail","mountain-railway","tram-car","bus","oncoming-bus","trolleybus","minibus","ambulance","fire-engine","police-car","oncoming-police-car","taxi","oncoming-taxi","automobile","oncoming-automobile","sport-utility-vehicle","pickup-truck","delivery-truck","articulated-lorry","tractor","racing-car","motorcycle","motor-scooter","manual-wheelchair","motorized-wheelchair","auto-rickshaw","bicycle","kick-scooter","skateboard","roller-skate","bus-stop","motorway","railway-track","oil-drum","fuel-pump","wheel","police-car-light","horizontal-traffic-light","vertical-traffic-light","stop-sign","construction","anchor","ring-buoy","sailboat","canoe","speedboat","passenger-ship","ferry","motor-boat","ship","airplane","small-airplane","airplane-departure","airplane-arrival","parachute","seat","helicopter","suspension-railway","mountain-cableway","aerial-tramway","satellite","rocket","flying-saucer","bellhop-bell","luggage","hourglass-done","hourglass-not-done","watch","alarm-clock","stopwatch","timer-clock","mantelpiece-clock","twelve-oclock","twelvethirty","one-oclock","onethirty","two-oclock","twothirty","three-oclock","threethirty","four-oclock","fourthirty","five-oclock","fivethirty","six-oclock","sixthirty","seven-oclock","seventhirty","eight-oclock","eightthirty","nine-oclock","ninethirty","ten-oclock","tenthirty","eleven-oclock","eleventhirty","new-moon","waxing-crescent-moon","first-quarter-moon","waxing-gibbous-moon","full-moon","waning-gibbous-moon","last-quarter-moon","waning-crescent-moon","crescent-moon","new-moon-face","first-quarter-moon-face","last-quarter-moon-face","thermometer","sun","full-moon-face","sun-with-face","ringed-planet","star","glowing-star","shooting-star","milky-way","cloud","sun-behind-cloud","cloud-with-lightning-and-rain","sun-behind-small-cloud","sun-behind-large-cloud","sun-behind-rain-cloud","cloud-with-rain","cloud-with-snow","cloud-with-lightning","tornado","fog","wind-face","cyclone","rainbow","closed-umbrella","umbrella","umbrella-with-rain-drops","umbrella-on-ground","high-voltage","snowflake","snowman","snowman-without-snow","comet","fire","droplet","water-wave"]},{"id":"activities","name":"Activities","emojis":["jackolantern","christmas-tree","fireworks","sparkler","firecracker","sparkles","balloon","party-popper","confetti-ball","tanabata-tree","pine-decoration","japanese-dolls","carp-streamer","wind-chime","moon-viewing-ceremony","red-envelope","ribbon","wrapped-gift","reminder-ribbon","admission-tickets","ticket","military-medal","trophy","sports-medal","1st-place-medal","2nd-place-medal","3rd-place-medal","soccer-ball","baseball","softball","basketball","volleyball","american-football","rugby-football","tennis","flying-disc","bowling","cricket-game","field-hockey","ice-hockey","lacrosse","ping-pong","badminton","boxing-glove","martial-arts-uniform","goal-net","flag-in-hole","ice-skate","fishing-pole","diving-mask","running-shirt","skis","sled","curling-stone","bullseye","yoyo","kite","pool-8-ball","crystal-ball","magic-wand","nazar-amulet","hamsa","video-game","joystick","slot-machine","game-die","puzzle-piece","teddy-bear","piata","mirror-ball","nesting-dolls","spade-suit","heart-suit","diamond-suit","club-suit","chess-pawn","joker","mahjong-red-dragon","flower-playing-cards","performing-arts","framed-picture","artist-palette","thread","sewing-needle","yarn","knot"]},{"id":"objects","name":"Objects","emojis":["glasses","sunglasses","goggles","lab-coat","safety-vest","necktie","tshirt","jeans","scarf","gloves","coat","socks","dress","kimono","sari","onepiece-swimsuit","briefs","shorts","bikini","womans-clothes","purse","handbag","clutch-bag","shopping-bags","backpack","thong-sandal","mans-shoe","running-shoe","hiking-boot","flat-shoe","highheeled-shoe","womans-sandal","ballet-shoes","womans-boot","crown","womans-hat","top-hat","graduation-cap","billed-cap","military-helmet","rescue-workers-helmet","prayer-beads","lipstick","ring","gem-stone","muted-speaker","speaker-low-volume","speaker-medium-volume","speaker-high-volume","loudspeaker","megaphone","postal-horn","bell","bell-with-slash","musical-score","musical-note","musical-notes","studio-microphone","level-slider","control-knobs","microphone","headphone","radio","saxophone","accordion","guitar","musical-keyboard","trumpet","violin","banjo","drum","long-drum","mobile-phone","mobile-phone-with-arrow","telephone","telephone-receiver","pager","fax-machine","battery","low-battery","electric-plug","laptop","desktop-computer","printer","keyboard","computer-mouse","trackball","computer-disk","floppy-disk","optical-disk","dvd","abacus","movie-camera","film-frames","film-projector","clapper-board","television","camera","camera-with-flash","video-camera","videocassette","magnifying-glass-tilted-left","magnifying-glass-tilted-right","candle","light-bulb","flashlight","red-paper-lantern","diya-lamp","notebook-with-decorative-cover","closed-book","open-book","green-book","blue-book","orange-book","books","notebook","ledger","page-with-curl","scroll","page-facing-up","newspaper","rolledup-newspaper","bookmark-tabs","bookmark","label","money-bag","coin","yen-banknote","dollar-banknote","euro-banknote","pound-banknote","money-with-wings","credit-card","receipt","chart-increasing-with-yen","envelope","email","incoming-envelope","envelope-with-arrow","outbox-tray","inbox-tray","package","closed-mailbox-with-raised-flag","closed-mailbox-with-lowered-flag","open-mailbox-with-raised-flag","open-mailbox-with-lowered-flag","postbox","ballot-box-with-ballot","pencil","black-nib","fountain-pen","pen","paintbrush","crayon","memo","briefcase","file-folder","open-file-folder","card-index-dividers","calendar","tearoff-calendar","spiral-notepad","spiral-calendar","card-index","chart-increasing","chart-decreasing","bar-chart","clipboard","pushpin","round-pushpin","paperclip","linked-paperclips","straight-ruler","triangular-ruler","scissors","card-file-box","file-cabinet","wastebasket","locked","unlocked","locked-with-pen","locked-with-key","key","old-key","hammer","axe","pick","hammer-and-pick","hammer-and-wrench","dagger","crossed-swords","water-pistol","boomerang","bow-and-arrow","shield","carpentry-saw","wrench","screwdriver","nut-and-bolt","gear","clamp","balance-scale","white-cane","link","chains","hook","toolbox","magnet","ladder","alembic","test-tube","petri-dish","dna","microscope","telescope","satellite-antenna","syringe","drop-of-blood","pill","adhesive-bandage","crutch","stethoscope","xray","door","elevator","mirror","window","bed","couch-and-lamp","chair","toilet","plunger","shower","bathtub","mouse-trap","razor","lotion-bottle","safety-pin","broom","basket","roll-of-paper","bucket","soap","bubbles","toothbrush","sponge","fire-extinguisher","shopping-cart","cigarette","coffin","headstone","funeral-urn","moai","placard","identification-card"]},{"id":"symbols","name":"Symbols","emojis":["atm-sign","litter-in-bin-sign","potable-water","wheelchair-symbol","mens-room","womens-room","restroom","baby-symbol","water-closet","passport-control","customs","baggage-claim","left-luggage","warning","children-crossing","no-entry","prohibited","no-bicycles","no-smoking","no-littering","nonpotable-water","no-pedestrians","no-mobile-phones","no-one-under-eighteen","radioactive","biohazard","up-arrow","upright-arrow","right-arrow","downright-arrow","down-arrow","downleft-arrow","left-arrow","upleft-arrow","updown-arrow","leftright-arrow","right-arrow-curving-left","left-arrow-curving-right","right-arrow-curving-up","right-arrow-curving-down","clockwise-vertical-arrows","counterclockwise-arrows-button","back-arrow","end-arrow","on-arrow","soon-arrow","top-arrow","place-of-worship","atom-symbol","om","star-of-david","wheel-of-dharma","yin-yang","latin-cross","orthodox-cross","star-and-crescent","peace-symbol","menorah","dotted-sixpointed-star","aries","taurus","gemini","cancer","leo","virgo","libra","scorpio","sagittarius","capricorn","aquarius","pisces","ophiuchus","shuffle-tracks-button","repeat-button","repeat-single-button","play-button","fastforward-button","next-track-button","play-or-pause-button","reverse-button","fast-reverse-button","last-track-button","upwards-button","fast-up-button","downwards-button","fast-down-button","pause-button","stop-button","record-button","eject-button","cinema","dim-button","bright-button","antenna-bars","vibration-mode","mobile-phone-off","female-sign","male-sign","transgender-symbol","multiply","plus","minus","divide","heavy-equals-sign","infinity","double-exclamation-mark","exclamation-question-mark","red-question-mark","white-question-mark","white-exclamation-mark","red-exclamation-mark","wavy-dash","currency-exchange","heavy-dollar-sign","medical-symbol","recycling-symbol","fleurdelis","trident-emblem","name-badge","japanese-symbol-for-beginner","hollow-red-circle","check-mark-button","check-box-with-check","check-mark","cross-mark","cross-mark-button","curly-loop","double-curly-loop","part-alternation-mark","eightspoked-asterisk","eightpointed-star","sparkle","copyright","registered","trade-mark","keycap","keycap","keycap-0","keycap-1","keycap-2","keycap-3","keycap-4","keycap-5","keycap-6","keycap-7","keycap-8","keycap-9","keycap-10","input-latin-uppercase","input-latin-lowercase","input-numbers","input-symbols","input-latin-letters","a-button-blood-type","ab-button-blood-type","b-button-blood-type","cl-button","cool-button","free-button","information","id-button","circled-m","new-button","ng-button","o-button-blood-type","ok-button","p-button","sos-button","up-button","vs-button","japanese-here-button","japanese-service-charge-button","japanese-monthly-amount-button","japanese-not-free-of-charge-button","japanese-reserved-button","japanese-bargain-button","japanese-discount-button","japanese-free-of-charge-button","japanese-prohibited-button","japanese-acceptable-button","japanese-application-button","japanese-passing-grade-button","japanese-vacancy-button","japanese-congratulations-button","japanese-secret-button","japanese-open-for-business-button","japanese-no-vacancy-button","red-circle","orange-circle","yellow-circle","green-circle","blue-circle","purple-circle","brown-circle","black-circle","white-circle","red-square","orange-square","yellow-square","green-square","blue-square","purple-square","brown-square","black-large-square","white-large-square","black-medium-square","white-medium-square","black-mediumsmall-square","white-mediumsmall-square","black-small-square","white-small-square","large-orange-diamond","large-blue-diamond","small-orange-diamond","small-blue-diamond","red-triangle-pointed-up","red-triangle-pointed-down","diamond-with-a-dot","radio-button","white-square-button","black-square-button"]},{"id":"flags","name":"Flags","emojis":["chequered-flag","triangular-flag","crossed-flags","black-flag","white-flag","rainbow-flag","transgender-flag","pirate-flag","flag-ascension-island","flag-andorra","flag-united-arab-emirates","flag-afghanistan","flag-antigua--barbuda","flag-anguilla","flag-albania","flag-armenia","flag-angola","flag-antarctica","flag-argentina","flag-american-samoa","flag-austria","flag-australia","flag-aruba","flag-land-islands","flag-azerbaijan","flag-bosnia--herzegovina","flag-barbados","flag-bangladesh","flag-belgium","flag-burkina-faso","flag-bulgaria","flag-bahrain","flag-burundi","flag-benin","flag-st-barthlemy","flag-bermuda","flag-brunei","flag-bolivia","flag-caribbean-netherlands","flag-brazil","flag-bahamas","flag-bhutan","flag-bouvet-island","flag-botswana","flag-belarus","flag-belize","flag-canada","flag-cocos-keeling-islands","flag-congo--kinshasa","flag-central-african-republic","flag-congo--brazzaville","flag-switzerland","flag-cte-divoire","flag-cook-islands","flag-chile","flag-cameroon","flag-china","flag-colombia","flag-clipperton-island","flag-costa-rica","flag-cuba","flag-cape-verde","flag-curaao","flag-christmas-island","flag-cyprus","flag-czechia","flag-germany","flag-diego-garcia","flag-djibouti","flag-denmark","flag-dominica","flag-dominican-republic","flag-algeria","flag-ceuta--melilla","flag-ecuador","flag-estonia","flag-egypt","flag-western-sahara","flag-eritrea","flag-spain","flag-ethiopia","flag-european-union","flag-finland","flag-fiji","flag-falkland-islands","flag-micronesia","flag-faroe-islands","flag-france","flag-gabon","flag-united-kingdom","flag-grenada","flag-georgia","flag-french-guiana","flag-guernsey","flag-ghana","flag-gibraltar","flag-greenland","flag-gambia","flag-guinea","flag-guadeloupe","flag-equatorial-guinea","flag-greece","flag-south-georgia--south-sandwich-islands","flag-guatemala","flag-guam","flag-guineabissau","flag-guyana","flag-hong-kong-sar-china","flag-heard--mcdonald-islands","flag-honduras","flag-croatia","flag-haiti","flag-hungary","flag-canary-islands","flag-indonesia","flag-ireland","flag-israel","flag-isle-of-man","flag-india","flag-british-indian-ocean-territory","flag-iraq","flag-iran","flag-iceland","flag-italy","flag-jersey","flag-jamaica","flag-jordan","flag-japan","flag-kenya","flag-kyrgyzstan","flag-cambodia","flag-kiribati","flag-comoros","flag-st-kitts--nevis","flag-north-korea","flag-south-korea","flag-kuwait","flag-cayman-islands","flag-kazakhstan","flag-laos","flag-lebanon","flag-st-lucia","flag-liechtenstein","flag-sri-lanka","flag-liberia","flag-lesotho","flag-lithuania","flag-luxembourg","flag-latvia","flag-libya","flag-morocco","flag-monaco","flag-moldova","flag-montenegro","flag-st-martin","flag-madagascar","flag-marshall-islands","flag-north-macedonia","flag-mali","flag-myanmar-burma","flag-mongolia","flag-macao-sar-china","flag-northern-mariana-islands","flag-martinique","flag-mauritania","flag-montserrat","flag-malta","flag-mauritius","flag-maldives","flag-malawi","flag-mexico","flag-malaysia","flag-mozambique","flag-namibia","flag-new-caledonia","flag-niger","flag-norfolk-island","flag-nigeria","flag-nicaragua","flag-netherlands","flag-norway","flag-nepal","flag-nauru","flag-niue","flag-new-zealand","flag-oman","flag-panama","flag-peru","flag-french-polynesia","flag-papua-new-guinea","flag-philippines","flag-pakistan","flag-poland","flag-st-pierre--miquelon","flag-pitcairn-islands","flag-puerto-rico","flag-palestinian-territories","flag-portugal","flag-palau","flag-paraguay","flag-qatar","flag-runion","flag-romania","flag-serbia","flag-russia","flag-rwanda","flag-saudi-arabia","flag-solomon-islands","flag-seychelles","flag-sudan","flag-sweden","flag-singapore","flag-st-helena","flag-slovenia","flag-svalbard--jan-mayen","flag-slovakia","flag-sierra-leone","flag-san-marino","flag-senegal","flag-somalia","flag-suriname","flag-south-sudan","flag-so-tom--prncipe","flag-el-salvador","flag-sint-maarten","flag-syria","flag-eswatini","flag-tristan-da-cunha","flag-turks--caicos-islands","flag-chad","flag-french-southern-territories","flag-togo","flag-thailand","flag-tajikistan","flag-tokelau","flag-timorleste","flag-turkmenistan","flag-tunisia","flag-tonga","flag-turkey","flag-trinidad--tobago","flag-tuvalu","flag-taiwan","flag-tanzania","flag-ukraine","flag-uganda","flag-us-outlying-islands","flag-united-nations","flag-united-states","flag-uruguay","flag-uzbekistan","flag-vatican-city","flag-st-vincent--grenadines","flag-venezuela","flag-british-virgin-islands","flag-us-virgin-islands","flag-vietnam","flag-vanuatu","flag-wallis--futuna","flag-samoa","flag-kosovo","flag-yemen","flag-mayotte","flag-south-africa","flag-zambia","flag-zimbabwe","flag-england","flag-scotland","flag-wales"]}],"emojis":{"grinning-face":{"a":"Grinning Face","b":"1F600","j":["face","grin","smile","happy","joy",":D"]},"grinning-face-with-big-eyes":{"a":"Grinning Face with Big Eyes","b":"1F603","j":["face","mouth","open","smile","happy","joy","haha",":D",":)","funny"]},"grinning-face-with-smiling-eyes":{"a":"Grinning Face with Smiling Eyes","b":"1F604","j":["eye","face","mouth","open","smile","happy","joy","funny","haha","laugh","like",":D",":)"]},"beaming-face-with-smiling-eyes":{"a":"Beaming Face with Smiling Eyes","b":"1F601","j":["eye","face","grin","smile","happy","joy","kawaii"]},"grinning-squinting-face":{"a":"Grinning Squinting Face","b":"1F606","j":["face","laugh","mouth","satisfied","smile","happy","joy","lol","haha","glad","XD"]},"grinning-face-with-sweat":{"a":"Grinning Face with Sweat","b":"1F605","j":["cold","face","open","smile","sweat","hot","happy","laugh","relief"]},"rolling-on-the-floor-laughing":{"a":"Rolling on the Floor Laughing","b":"1F923","j":["face","floor","laugh","rofl","rolling","rotfl","laughing","lol","haha"]},"face-with-tears-of-joy":{"a":"Face with Tears of Joy","b":"1F602","j":["face","joy","laugh","tear","cry","tears","weep","happy","happytears","haha"]},"slightly-smiling-face":{"a":"Slightly Smiling Face","b":"1F642","j":["face","smile"]},"upsidedown-face":{"a":"Upside-Down Face","b":"1F643","j":["face","upside-down","upside_down_face","flipped","silly","smile"]},"melting-face":{"a":"⊛ Melting Face","b":"1FAE0","j":["disappear","dissolve","liquid","melt"]},"winking-face":{"a":"Winking Face","b":"1F609","j":["face","wink","happy","mischievous","secret",";)","smile","eye"]},"smiling-face-with-smiling-eyes":{"a":"Smiling Face with Smiling Eyes","b":"1F60A","j":["blush","eye","face","smile","happy","flushed","crush","embarrassed","shy","joy"]},"smiling-face-with-halo":{"a":"Smiling Face with Halo","b":"1F607","j":["angel","face","fantasy","halo","innocent","heaven"]},"smiling-face-with-hearts":{"a":"Smiling Face with Hearts","b":"1F970","j":["adore","crush","hearts","in love","face","love","like","affection","valentines","infatuation"]},"smiling-face-with-hearteyes":{"a":"Smiling Face with Heart-Eyes","b":"1F60D","j":["eye","face","love","smile","smiling face with heart-eyes","smiling_face_with_heart_eyes","like","affection","valentines","infatuation","crush","heart"]},"starstruck":{"a":"Star-Struck","b":"1F929","j":["eyes","face","grinning","star","star-struck","starry-eyed","star_struck","smile","starry"]},"face-blowing-a-kiss":{"a":"Face Blowing a Kiss","b":"1F618","j":["face","kiss","love","like","affection","valentines","infatuation"]},"kissing-face":{"a":"Kissing Face","b":"1F617","j":["face","kiss","love","like","3","valentines","infatuation"]},"smiling-face":{"a":"Smiling Face","b":"263A","j":["face","outlined","relaxed","smile","blush","massage","happiness"]},"kissing-face-with-closed-eyes":{"a":"Kissing Face with Closed Eyes","b":"1F61A","j":["closed","eye","face","kiss","love","like","affection","valentines","infatuation"]},"kissing-face-with-smiling-eyes":{"a":"Kissing Face with Smiling Eyes","b":"1F619","j":["eye","face","kiss","smile","affection","valentines","infatuation"]},"smiling-face-with-tear":{"a":"Smiling Face with Tear","b":"1F972","j":["grateful","proud","relieved","smiling","tear","touched","sad","cry","pretend"]},"face-savoring-food":{"a":"Face Savoring Food","b":"1F60B","j":["delicious","face","savouring","smile","yum","happy","joy","tongue","silly","yummy","nom"]},"face-with-tongue":{"a":"Face with Tongue","b":"1F61B","j":["face","tongue","prank","childish","playful","mischievous","smile"]},"winking-face-with-tongue":{"a":"Winking Face with Tongue","b":"1F61C","j":["eye","face","joke","tongue","wink","prank","childish","playful","mischievous","smile"]},"zany-face":{"a":"Zany Face","b":"1F92A","j":["eye","goofy","large","small","face","crazy"]},"squinting-face-with-tongue":{"a":"Squinting Face with Tongue","b":"1F61D","j":["eye","face","horrible","taste","tongue","prank","playful","mischievous","smile"]},"moneymouth-face":{"a":"Money-Mouth Face","b":"1F911","j":["face","money","money-mouth face","mouth","money_mouth_face","rich","dollar"]},"smiling-face-with-open-hands":{"a":"Smiling Face with Open Hands","b":"1F917","j":["face","hug","hugging","open hands","smiling face","hugging_face","smile"]},"face-with-hand-over-mouth":{"a":"Face with Hand over Mouth","b":"1F92D","j":["whoops","shock","sudden realization","surprise","face"]},"face-with-open-eyes-and-hand-over-mouth":{"a":"⊛ Face with Open Eyes and Hand over Mouth","b":"1FAE2","j":["amazement","awe","disbelief","embarrass","scared","surprise"]},"face-with-peeking-eye":{"a":"⊛ Face with Peeking Eye","b":"1FAE3","j":["captivated","peep","stare"]},"shushing-face":{"a":"Shushing Face","b":"1F92B","j":["quiet","shush","face","shhh"]},"thinking-face":{"a":"Thinking Face","b":"1F914","j":["face","thinking","hmmm","think","consider"]},"saluting-face":{"a":"⊛ Saluting Face","b":"1FAE1","j":["ok","salute","sunny","troops","yes"]},"zippermouth-face":{"a":"Zipper-Mouth Face","b":"1F910","j":["face","mouth","zipper","zipper-mouth face","zipper_mouth_face","sealed","secret"]},"face-with-raised-eyebrow":{"a":"Face with Raised Eyebrow","b":"1F928","j":["distrust","skeptic","disapproval","disbelief","mild surprise","scepticism","face","surprise"]},"neutral-face":{"a":"Neutral Face","b":"1F610","j":["deadpan","face","meh","neutral","indifference",":|"]},"expressionless-face":{"a":"Expressionless Face","b":"1F611","j":["expressionless","face","inexpressive","meh","unexpressive","indifferent","-_-","deadpan"]},"face-without-mouth":{"a":"Face Without Mouth","b":"1F636","j":["face","mouth","quiet","silent","hellokitty"]},"dotted-line-face":{"a":"⊛ Dotted Line Face","b":"1FAE5","j":["depressed","disappear","hide","introvert","invisible"]},"face-in-clouds":{"a":"Face in Clouds","b":"1F636-200D-1F32B-FE0F","j":["absentminded","face in clouds","face in the fog","head in clouds"]},"smirking-face":{"a":"Smirking Face","b":"1F60F","j":["face","smirk","smile","mean","prank","smug","sarcasm"]},"unamused-face":{"a":"Unamused Face","b":"1F612","j":["face","unamused","unhappy","indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"]},"face-with-rolling-eyes":{"a":"Face with Rolling Eyes","b":"1F644","j":["eyeroll","eyes","face","rolling","frustrated"]},"grimacing-face":{"a":"Grimacing Face","b":"1F62C","j":["face","grimace","teeth"]},"face-exhaling":{"a":"Face Exhaling","b":"1F62E-200D-1F4A8","j":["exhale","face exhaling","gasp","groan","relief","whisper","whistle"]},"lying-face":{"a":"Lying Face","b":"1F925","j":["face","lie","pinocchio"]},"relieved-face":{"a":"Relieved Face","b":"1F60C","j":["face","relieved","relaxed","phew","massage","happiness"]},"pensive-face":{"a":"Pensive Face","b":"1F614","j":["dejected","face","pensive","sad","depressed","upset"]},"sleepy-face":{"a":"Sleepy Face","b":"1F62A","j":["face","sleep","tired","rest","nap"]},"drooling-face":{"a":"Drooling Face","b":"1F924","j":["drooling","face"]},"sleeping-face":{"a":"Sleeping Face","b":"1F634","j":["face","sleep","zzz","tired","sleepy","night"]},"face-with-medical-mask":{"a":"Face with Medical Mask","b":"1F637","j":["cold","doctor","face","mask","sick","ill","disease"]},"face-with-thermometer":{"a":"Face with Thermometer","b":"1F912","j":["face","ill","sick","thermometer","temperature","cold","fever"]},"face-with-headbandage":{"a":"Face with Head-Bandage","b":"1F915","j":["bandage","face","face with head-bandage","hurt","injury","face_with_head_bandage","injured","clumsy"]},"nauseated-face":{"a":"Nauseated Face","b":"1F922","j":["face","nauseated","vomit","gross","green","sick","throw up","ill"]},"face-vomiting":{"a":"Face Vomiting","b":"1F92E","j":["puke","sick","vomit","face"]},"sneezing-face":{"a":"Sneezing Face","b":"1F927","j":["face","gesundheit","sneeze","sick","allergy"]},"hot-face":{"a":"Hot Face","b":"1F975","j":["feverish","heat stroke","hot","red-faced","sweating","face","heat","red"]},"cold-face":{"a":"Cold Face","b":"1F976","j":["blue-faced","cold","freezing","frostbite","icicles","face","blue","frozen"]},"woozy-face":{"a":"Woozy Face","b":"1F974","j":["dizzy","intoxicated","tipsy","uneven eyes","wavy mouth","face","wavy"]},"face-with-crossedout-eyes":{"a":"Face with Crossed-out Eyes","b":"1F635","j":["crossed-out eyes","dead","face","face with crossed-out eyes","knocked out","dizzy_face","spent","unconscious","xox","dizzy"]},"face-with-spiral-eyes":{"a":"Face with Spiral Eyes","b":"1F635-200D-1F4AB","j":["dizzy","face with spiral eyes","hypnotized","spiral","trouble","whoa"]},"exploding-head":{"a":"Exploding Head","b":"1F92F","j":["mind blown","shocked","face","mind","blown"]},"cowboy-hat-face":{"a":"Cowboy Hat Face","b":"1F920","j":["cowboy","cowgirl","face","hat"]},"partying-face":{"a":"Partying Face","b":"1F973","j":["celebration","hat","horn","party","face","woohoo"]},"disguised-face":{"a":"Disguised Face","b":"1F978","j":["disguise","face","glasses","incognito","nose","pretent","brows","moustache"]},"smiling-face-with-sunglasses":{"a":"Smiling Face with Sunglasses","b":"1F60E","j":["bright","cool","face","sun","sunglasses","smile","summer","beach","sunglass"]},"nerd-face":{"a":"Nerd Face","b":"1F913","j":["face","geek","nerd","nerdy","dork"]},"face-with-monocle":{"a":"Face with Monocle","b":"1F9D0","j":["stuffy","wealthy","face"]},"confused-face":{"a":"Confused Face","b":"1F615","j":["confused","face","meh","indifference","huh","weird","hmmm",":/"]},"face-with-diagonal-mouth":{"a":"⊛ Face with Diagonal Mouth","b":"1FAE4","j":["disappointed","meh","skeptical","unsure"]},"worried-face":{"a":"Worried Face","b":"1F61F","j":["face","worried","concern","nervous",":("]},"slightly-frowning-face":{"a":"Slightly Frowning Face","b":"1F641","j":["face","frown","frowning","disappointed","sad","upset"]},"frowning-face":{"a":"Frowning Face","b":"2639","j":["face","frown","sad","upset"]},"face-with-open-mouth":{"a":"Face with Open Mouth","b":"1F62E","j":["face","mouth","open","sympathy","surprise","impressed","wow","whoa",":O"]},"hushed-face":{"a":"Hushed Face","b":"1F62F","j":["face","hushed","stunned","surprised","woo","shh"]},"astonished-face":{"a":"Astonished Face","b":"1F632","j":["astonished","face","shocked","totally","xox","surprised","poisoned"]},"flushed-face":{"a":"Flushed Face","b":"1F633","j":["dazed","face","flushed","blush","shy","flattered"]},"pleading-face":{"a":"Pleading Face","b":"1F97A","j":["begging","mercy","puppy eyes","face"]},"face-holding-back-tears":{"a":"⊛ Face Holding Back Tears","b":"1F979","j":["angry","cry","proud","resist","sad"]},"frowning-face-with-open-mouth":{"a":"Frowning Face with Open Mouth","b":"1F626","j":["face","frown","mouth","open","aw","what"]},"anguished-face":{"a":"Anguished Face","b":"1F627","j":["anguished","face","stunned","nervous"]},"fearful-face":{"a":"Fearful Face","b":"1F628","j":["face","fear","fearful","scared","terrified","nervous","oops","huh"]},"anxious-face-with-sweat":{"a":"Anxious Face with Sweat","b":"1F630","j":["blue","cold","face","rushed","sweat","nervous"]},"sad-but-relieved-face":{"a":"Sad but Relieved Face","b":"1F625","j":["disappointed","face","relieved","whew","phew","sweat","nervous"]},"crying-face":{"a":"Crying Face","b":"1F622","j":["cry","face","sad","tear","tears","depressed","upset",":'("]},"loudly-crying-face":{"a":"Loudly Crying Face","b":"1F62D","j":["cry","face","sad","sob","tear","tears","upset","depressed"]},"face-screaming-in-fear":{"a":"Face Screaming in Fear","b":"1F631","j":["face","fear","munch","scared","scream","omg"]},"confounded-face":{"a":"Confounded Face","b":"1F616","j":["confounded","face","confused","sick","unwell","oops",":S"]},"persevering-face":{"a":"Persevering Face","b":"1F623","j":["face","persevere","sick","no","upset","oops"]},"disappointed-face":{"a":"Disappointed Face","b":"1F61E","j":["disappointed","face","sad","upset","depressed",":("]},"downcast-face-with-sweat":{"a":"Downcast Face with Sweat","b":"1F613","j":["cold","face","sweat","hot","sad","tired","exercise"]},"weary-face":{"a":"Weary Face","b":"1F629","j":["face","tired","weary","sleepy","sad","frustrated","upset"]},"tired-face":{"a":"Tired Face","b":"1F62B","j":["face","tired","sick","whine","upset","frustrated"]},"yawning-face":{"a":"Yawning Face","b":"1F971","j":["bored","tired","yawn","sleepy"]},"face-with-steam-from-nose":{"a":"Face with Steam From Nose","b":"1F624","j":["face","triumph","won","gas","phew","proud","pride"]},"pouting-face":{"a":"Pouting Face","b":"1F621","j":["angry","face","mad","pouting","rage","red","hate","despise"]},"angry-face":{"a":"Angry Face","b":"1F620","j":["anger","angry","face","mad","annoyed","frustrated"]},"face-with-symbols-on-mouth":{"a":"Face with Symbols on Mouth","b":"1F92C","j":["swearing","cursing","face","cussing","profanity","expletive"]},"smiling-face-with-horns":{"a":"Smiling Face with Horns","b":"1F608","j":["face","fairy tale","fantasy","horns","smile","devil"]},"angry-face-with-horns":{"a":"Angry Face with Horns","b":"1F47F","j":["demon","devil","face","fantasy","imp","angry","horns"]},"skull":{"a":"Skull","b":"1F480","j":["death","face","fairy tale","monster","dead","skeleton","creepy"]},"skull-and-crossbones":{"a":"Skull and Crossbones","b":"2620","j":["crossbones","death","face","monster","skull","poison","danger","deadly","scary","pirate","evil"]},"pile-of-poo":{"a":"Pile of Poo","b":"1F4A9","j":["dung","face","monster","poo","poop","hankey","shitface","fail","turd","shit"]},"clown-face":{"a":"Clown Face","b":"1F921","j":["clown","face"]},"ogre":{"a":"Ogre","b":"1F479","j":["creature","face","fairy tale","fantasy","monster","troll","red","mask","halloween","scary","creepy","devil","demon","japanese"]},"goblin":{"a":"Goblin","b":"1F47A","j":["creature","face","fairy tale","fantasy","monster","red","evil","mask","scary","creepy","japanese"]},"ghost":{"a":"Ghost","b":"1F47B","j":["creature","face","fairy tale","fantasy","monster","halloween","spooky","scary"]},"alien":{"a":"Alien","b":"1F47D","j":["creature","extraterrestrial","face","fantasy","ufo","UFO","paul","weird","outer_space"]},"alien-monster":{"a":"Alien Monster","b":"1F47E","j":["alien","creature","extraterrestrial","face","monster","ufo","game","arcade","play"]},"robot":{"a":"Robot","b":"1F916","j":["face","monster","computer","machine","bot"]},"grinning-cat":{"a":"Grinning Cat","b":"1F63A","j":["cat","face","grinning","mouth","open","smile","animal","cats","happy"]},"grinning-cat-with-smiling-eyes":{"a":"Grinning Cat with Smiling Eyes","b":"1F638","j":["cat","eye","face","grin","smile","animal","cats"]},"cat-with-tears-of-joy":{"a":"Cat with Tears of Joy","b":"1F639","j":["cat","face","joy","tear","animal","cats","haha","happy","tears"]},"smiling-cat-with-hearteyes":{"a":"Smiling Cat with Heart-Eyes","b":"1F63B","j":["cat","eye","face","heart","love","smile","smiling cat with heart-eyes","smiling_cat_with_heart_eyes","animal","like","affection","cats","valentines"]},"cat-with-wry-smile":{"a":"Cat with Wry Smile","b":"1F63C","j":["cat","face","ironic","smile","wry","animal","cats","smirk"]},"kissing-cat":{"a":"Kissing Cat","b":"1F63D","j":["cat","eye","face","kiss","animal","cats"]},"weary-cat":{"a":"Weary Cat","b":"1F640","j":["cat","face","oh","surprised","weary","animal","cats","munch","scared","scream"]},"crying-cat":{"a":"Crying Cat","b":"1F63F","j":["cat","cry","face","sad","tear","animal","tears","weep","cats","upset"]},"pouting-cat":{"a":"Pouting Cat","b":"1F63E","j":["cat","face","pouting","animal","cats"]},"seenoevil-monkey":{"a":"See-No-Evil Monkey","b":"1F648","j":["evil","face","forbidden","monkey","see","see-no-evil monkey","see_no_evil_monkey","animal","nature","haha"]},"hearnoevil-monkey":{"a":"Hear-No-Evil Monkey","b":"1F649","j":["evil","face","forbidden","hear","hear-no-evil monkey","monkey","hear_no_evil_monkey","animal","nature"]},"speaknoevil-monkey":{"a":"Speak-No-Evil Monkey","b":"1F64A","j":["evil","face","forbidden","monkey","speak","speak-no-evil monkey","speak_no_evil_monkey","animal","nature","omg"]},"kiss-mark":{"a":"Kiss Mark","b":"1F48B","j":["kiss","lips","face","love","like","affection","valentines"]},"love-letter":{"a":"Love Letter","b":"1F48C","j":["heart","letter","love","mail","email","like","affection","envelope","valentines"]},"heart-with-arrow":{"a":"Heart with Arrow","b":"1F498","j":["arrow","cupid","love","like","heart","affection","valentines"]},"heart-with-ribbon":{"a":"Heart with Ribbon","b":"1F49D","j":["ribbon","valentine","love","valentines"]},"sparkling-heart":{"a":"Sparkling Heart","b":"1F496","j":["excited","sparkle","love","like","affection","valentines"]},"growing-heart":{"a":"Growing Heart","b":"1F497","j":["excited","growing","nervous","pulse","like","love","affection","valentines","pink"]},"beating-heart":{"a":"Beating Heart","b":"1F493","j":["beating","heartbeat","pulsating","love","like","affection","valentines","pink","heart"]},"revolving-hearts":{"a":"Revolving Hearts","b":"1F49E","j":["revolving","love","like","affection","valentines"]},"two-hearts":{"a":"Two Hearts","b":"1F495","j":["love","like","affection","valentines","heart"]},"heart-decoration":{"a":"Heart Decoration","b":"1F49F","j":["heart","purple-square","love","like"]},"heart-exclamation":{"a":"Heart Exclamation","b":"2763","j":["exclamation","mark","punctuation","decoration","love"]},"broken-heart":{"a":"Broken Heart","b":"1F494","j":["break","broken","sad","sorry","heart","heartbreak"]},"heart-on-fire":{"a":"Heart on Fire","b":"2764-FE0F-200D-1F525","j":["burn","heart","heart on fire","love","lust","sacred heart"]},"mending-heart":{"a":"Mending Heart","b":"2764-FE0F-200D-1FA79","j":["healthier","improving","mending","mending heart","recovering","recuperating","well"]},"red-heart":{"a":"Red Heart","b":"2764","j":["heart","love","like","valentines"]},"orange-heart":{"a":"Orange Heart","b":"1F9E1","j":["orange","love","like","affection","valentines"]},"yellow-heart":{"a":"Yellow Heart","b":"1F49B","j":["yellow","love","like","affection","valentines"]},"green-heart":{"a":"Green Heart","b":"1F49A","j":["green","love","like","affection","valentines"]},"blue-heart":{"a":"Blue Heart","b":"1F499","j":["blue","love","like","affection","valentines"]},"purple-heart":{"a":"Purple Heart","b":"1F49C","j":["purple","love","like","affection","valentines"]},"brown-heart":{"a":"Brown Heart","b":"1F90E","j":["brown","heart","coffee"]},"black-heart":{"a":"Black Heart","b":"1F5A4","j":["black","evil","wicked"]},"white-heart":{"a":"White Heart","b":"1F90D","j":["heart","white","pure"]},"hundred-points":{"a":"Hundred Points","b":"1F4AF","j":["100","full","hundred","score","perfect","numbers","century","exam","quiz","test","pass"]},"anger-symbol":{"a":"Anger Symbol","b":"1F4A2","j":["angry","comic","mad"]},"collision":{"a":"Collision","b":"1F4A5","j":["boom","comic","bomb","explode","explosion","blown"]},"dizzy":{"a":"Dizzy","b":"1F4AB","j":["comic","star","sparkle","shoot","magic"]},"sweat-droplets":{"a":"Sweat Droplets","b":"1F4A6","j":["comic","splashing","sweat","water","drip","oops"]},"dashing-away":{"a":"Dashing Away","b":"1F4A8","j":["comic","dash","running","wind","air","fast","shoo","fart","smoke","puff"]},"hole":{"a":"Hole","b":"1F573","j":["embarrassing"]},"bomb":{"a":"Bomb","b":"1F4A3","j":["comic","boom","explode","explosion","terrorism"]},"speech-balloon":{"a":"Speech Balloon","b":"1F4AC","j":["balloon","bubble","comic","dialog","speech","words","message","talk","chatting"]},"eye-in-speech-bubble":{"a":"Eye in Speech Bubble","b":"1F441-FE0F-200D-1F5E8-FE0F","j":["eye","speech bubble","witness","info"]},"left-speech-bubble":{"a":"Left Speech Bubble","b":"1F5E8","j":["dialog","speech","words","message","talk","chatting"]},"right-anger-bubble":{"a":"Right Anger Bubble","b":"1F5EF","j":["angry","balloon","bubble","mad","caption","speech","thinking"]},"thought-balloon":{"a":"Thought Balloon","b":"1F4AD","j":["balloon","bubble","comic","thought","cloud","speech","thinking","dream"]},"zzz":{"a":"Zzz","b":"1F4A4","j":["comic","sleep","sleepy","tired","dream"]},"waving-hand":{"a":"Waving Hand","b":"1F44B","j":["hand","wave","waving","hands","gesture","goodbye","solong","farewell","hello","hi","palm"]},"raised-back-of-hand":{"a":"Raised Back of Hand","b":"1F91A","j":["backhand","raised","fingers"]},"hand-with-fingers-splayed":{"a":"Hand with Fingers Splayed","b":"1F590","j":["finger","hand","splayed","fingers","palm"]},"raised-hand":{"a":"Raised Hand","b":"270B","j":["hand","high 5","high five","fingers","stop","highfive","palm","ban"]},"vulcan-salute":{"a":"Vulcan Salute","b":"1F596","j":["finger","hand","spock","vulcan","fingers","star trek"]},"rightwards-hand":{"a":"⊛ Rightwards Hand","b":"1FAF1","j":["hand","right","rightward"]},"leftwards-hand":{"a":"⊛ Leftwards Hand","b":"1FAF2","j":["hand","left","leftward"]},"palm-down-hand":{"a":"⊛ Palm Down Hand","b":"1FAF3","j":["dismiss","drop","shoo"]},"palm-up-hand":{"a":"⊛ Palm Up Hand","b":"1FAF4","j":["beckon","catch","come","offer"]},"ok-hand":{"a":"Ok Hand","b":"1F44C","j":["hand","OK","fingers","limbs","perfect","ok","okay"]},"pinched-fingers":{"a":"Pinched Fingers","b":"1F90C","j":["fingers","hand gesture","interrogation","pinched","sarcastic","size","tiny","small"]},"pinching-hand":{"a":"Pinching Hand","b":"1F90F","j":["small amount","tiny","small","size"]},"victory-hand":{"a":"Victory Hand","b":"270C","j":["hand","v","victory","fingers","ohyeah","peace","two"]},"crossed-fingers":{"a":"Crossed Fingers","b":"1F91E","j":["cross","finger","hand","luck","good","lucky"]},"hand-with-index-finger-and-thumb-crossed":{"a":"⊛ Hand with Index Finger and Thumb Crossed","b":"1FAF0","j":["expensive","heart","love","money","snap"]},"loveyou-gesture":{"a":"Love-You Gesture","b":"1F91F","j":["hand","ILY","love-you gesture","love_you_gesture","fingers","gesture"]},"sign-of-the-horns":{"a":"Sign of the Horns","b":"1F918","j":["finger","hand","horns","rock-on","fingers","evil_eye","sign_of_horns","rock_on"]},"call-me-hand":{"a":"Call Me Hand","b":"1F919","j":["call","hand","hands","gesture"]},"backhand-index-pointing-left":{"a":"Backhand Index Pointing Left","b":"1F448","j":["backhand","finger","hand","index","point","direction","fingers","left"]},"backhand-index-pointing-right":{"a":"Backhand Index Pointing Right","b":"1F449","j":["backhand","finger","hand","index","point","fingers","direction","right"]},"backhand-index-pointing-up":{"a":"Backhand Index Pointing Up","b":"1F446","j":["backhand","finger","hand","point","up","fingers","direction"]},"middle-finger":{"a":"Middle Finger","b":"1F595","j":["finger","hand","fingers","rude","middle","flipping"]},"backhand-index-pointing-down":{"a":"Backhand Index Pointing Down","b":"1F447","j":["backhand","down","finger","hand","point","fingers","direction"]},"index-pointing-up":{"a":"Index Pointing Up","b":"261D","j":["finger","hand","index","point","up","fingers","direction"]},"index-pointing-at-the-viewer":{"a":"⊛ Index Pointing at the Viewer","b":"1FAF5","j":["point","you"]},"thumbs-up":{"a":"Thumbs Up","b":"1F44D","j":["+1","hand","thumb","up","thumbsup","yes","awesome","good","agree","accept","cool","like"]},"thumbs-down":{"a":"Thumbs Down","b":"1F44E","j":["-1","down","hand","thumb","thumbsdown","no","dislike"]},"raised-fist":{"a":"Raised Fist","b":"270A","j":["clenched","fist","hand","punch","fingers","grasp"]},"oncoming-fist":{"a":"Oncoming Fist","b":"1F44A","j":["clenched","fist","hand","punch","angry","violence","hit","attack"]},"leftfacing-fist":{"a":"Left-Facing Fist","b":"1F91B","j":["fist","left-facing fist","leftwards","left_facing_fist","hand","fistbump"]},"rightfacing-fist":{"a":"Right-Facing Fist","b":"1F91C","j":["fist","right-facing fist","rightwards","right_facing_fist","hand","fistbump"]},"clapping-hands":{"a":"Clapping Hands","b":"1F44F","j":["clap","hand","hands","praise","applause","congrats","yay"]},"raising-hands":{"a":"Raising Hands","b":"1F64C","j":["celebration","gesture","hand","hooray","raised","yea","hands"]},"heart-hands":{"a":"⊛ Heart Hands","b":"1FAF6","j":["love"]},"open-hands":{"a":"Open Hands","b":"1F450","j":["hand","open","fingers","butterfly","hands"]},"palms-up-together":{"a":"Palms Up Together","b":"1F932","j":["prayer","cupped hands","hands","gesture","cupped"]},"handshake":{"a":"Handshake","b":"1F91D","j":["agreement","hand","meeting","shake"]},"folded-hands":{"a":"Folded Hands","b":"1F64F","j":["ask","hand","high 5","high five","please","pray","thanks","hope","wish","namaste","highfive"]},"writing-hand":{"a":"Writing Hand","b":"270D","j":["hand","write","lower_left_ballpoint_pen","stationery","compose"]},"nail-polish":{"a":"Nail Polish","b":"1F485","j":["care","cosmetics","manicure","nail","polish","beauty","finger","fashion"]},"selfie":{"a":"Selfie","b":"1F933","j":["camera","phone"]},"flexed-biceps":{"a":"Flexed Biceps","b":"1F4AA","j":["biceps","comic","flex","muscle","arm","hand","summer","strong"]},"mechanical-arm":{"a":"Mechanical Arm","b":"1F9BE","j":["accessibility","prosthetic"]},"mechanical-leg":{"a":"Mechanical Leg","b":"1F9BF","j":["accessibility","prosthetic"]},"leg":{"a":"Leg","b":"1F9B5","j":["kick","limb"]},"foot":{"a":"Foot","b":"1F9B6","j":["kick","stomp"]},"ear":{"a":"Ear","b":"1F442","j":["body","face","hear","sound","listen"]},"ear-with-hearing-aid":{"a":"Ear with Hearing Aid","b":"1F9BB","j":["accessibility","hard of hearing"]},"nose":{"a":"Nose","b":"1F443","j":["body","smell","sniff"]},"brain":{"a":"Brain","b":"1F9E0","j":["intelligent","smart"]},"anatomical-heart":{"a":"Anatomical Heart","b":"1FAC0","j":["anatomical","cardiology","heart","organ","pulse","health","heartbeat"]},"lungs":{"a":"Lungs","b":"1FAC1","j":["breath","exhalation","inhalation","organ","respiration","breathe"]},"tooth":{"a":"Tooth","b":"1F9B7","j":["dentist","teeth"]},"bone":{"a":"Bone","b":"1F9B4","j":["skeleton"]},"eyes":{"a":"Eyes","b":"1F440","j":["eye","face","look","watch","stalk","peek","see"]},"eye":{"a":"Eye","b":"1F441","j":["body","face","look","see","watch","stare"]},"tongue":{"a":"Tongue","b":"1F445","j":["body","mouth","playful"]},"mouth":{"a":"Mouth","b":"1F444","j":["lips","kiss"]},"biting-lip":{"a":"⊛ Biting Lip","b":"1FAE6","j":["anxious","fear","flirting","nervous","uncomfortable","worried"]},"baby":{"a":"Baby","b":"1F476","j":["young","child","boy","girl","toddler"]},"child":{"a":"Child","b":"1F9D2","j":["gender-neutral","unspecified gender","young"]},"boy":{"a":"Boy","b":"1F466","j":["young","man","male","guy","teenager"]},"girl":{"a":"Girl","b":"1F467","j":["Virgo","young","zodiac","female","woman","teenager"]},"person":{"a":"Person","b":"1F9D1","j":["adult","gender-neutral","unspecified gender"]},"person-blond-hair":{"a":"Person: Blond Hair","b":"1F471","j":["blond","blond-haired person","hair","person: blond hair","hairstyle"]},"man":{"a":"Man","b":"1F468","j":["adult","mustache","father","dad","guy","classy","sir","moustache"]},"person-beard":{"a":"Person: Beard","b":"1F9D4","j":["beard","person","person: beard","bewhiskered","man_beard"]},"man-beard":{"a":"Man: Beard","b":"1F9D4-200D-2642-FE0F","j":["beard","man","man: beard"]},"woman-beard":{"a":"Woman: Beard","b":"1F9D4-200D-2640-FE0F","j":["beard","woman","woman: beard"]},"man-red-hair":{"a":"Man: Red Hair","b":"1F468-200D-1F9B0","j":["adult","man","red hair","hairstyle"]},"man-curly-hair":{"a":"Man: Curly Hair","b":"1F468-200D-1F9B1","j":["adult","curly hair","man","hairstyle"]},"man-white-hair":{"a":"Man: White Hair","b":"1F468-200D-1F9B3","j":["adult","man","white hair","old","elder"]},"man-bald":{"a":"Man: Bald","b":"1F468-200D-1F9B2","j":["adult","bald","man","hairless"]},"woman":{"a":"Woman","b":"1F469","j":["adult","female","girls","lady"]},"woman-red-hair":{"a":"Woman: Red Hair","b":"1F469-200D-1F9B0","j":["adult","red hair","woman","hairstyle"]},"person-red-hair":{"a":"Person: Red Hair","b":"1F9D1-200D-1F9B0","j":["adult","gender-neutral","person","red hair","unspecified gender","hairstyle"]},"woman-curly-hair":{"a":"Woman: Curly Hair","b":"1F469-200D-1F9B1","j":["adult","curly hair","woman","hairstyle"]},"person-curly-hair":{"a":"Person: Curly Hair","b":"1F9D1-200D-1F9B1","j":["adult","curly hair","gender-neutral","person","unspecified gender","hairstyle"]},"woman-white-hair":{"a":"Woman: White Hair","b":"1F469-200D-1F9B3","j":["adult","white hair","woman","old","elder"]},"person-white-hair":{"a":"Person: White Hair","b":"1F9D1-200D-1F9B3","j":["adult","gender-neutral","person","unspecified gender","white hair","elder","old"]},"woman-bald":{"a":"Woman: Bald","b":"1F469-200D-1F9B2","j":["adult","bald","woman","hairless"]},"person-bald":{"a":"Person: Bald","b":"1F9D1-200D-1F9B2","j":["adult","bald","gender-neutral","person","unspecified gender","hairless"]},"woman-blond-hair":{"a":"Woman: Blond Hair","b":"1F471-200D-2640-FE0F","j":["blond-haired woman","blonde","hair","woman","woman: blond hair","female","girl","person"]},"man-blond-hair":{"a":"Man: Blond Hair","b":"1F471-200D-2642-FE0F","j":["blond","blond-haired man","hair","man","man: blond hair","male","boy","blonde","guy","person"]},"older-person":{"a":"Older Person","b":"1F9D3","j":["adult","gender-neutral","old","unspecified gender","human","elder","senior"]},"old-man":{"a":"Old Man","b":"1F474","j":["adult","man","old","human","male","men","elder","senior"]},"old-woman":{"a":"Old Woman","b":"1F475","j":["adult","old","woman","human","female","women","lady","elder","senior"]},"person-frowning":{"a":"Person Frowning","b":"1F64D","j":["frown","gesture","worried"]},"man-frowning":{"a":"Man Frowning","b":"1F64D-200D-2642-FE0F","j":["frowning","gesture","man","male","boy","sad","depressed","discouraged","unhappy"]},"woman-frowning":{"a":"Woman Frowning","b":"1F64D-200D-2640-FE0F","j":["frowning","gesture","woman","female","girl","sad","depressed","discouraged","unhappy"]},"person-pouting":{"a":"Person Pouting","b":"1F64E","j":["gesture","pouting","upset"]},"man-pouting":{"a":"Man Pouting","b":"1F64E-200D-2642-FE0F","j":["gesture","man","pouting","male","boy"]},"woman-pouting":{"a":"Woman Pouting","b":"1F64E-200D-2640-FE0F","j":["gesture","pouting","woman","female","girl"]},"person-gesturing-no":{"a":"Person Gesturing No","b":"1F645","j":["forbidden","gesture","hand","person gesturing NO","prohibited","decline"]},"man-gesturing-no":{"a":"Man Gesturing No","b":"1F645-200D-2642-FE0F","j":["forbidden","gesture","hand","man","man gesturing NO","prohibited","male","boy","nope"]},"woman-gesturing-no":{"a":"Woman Gesturing No","b":"1F645-200D-2640-FE0F","j":["forbidden","gesture","hand","prohibited","woman","woman gesturing NO","female","girl","nope"]},"person-gesturing-ok":{"a":"Person Gesturing Ok","b":"1F646","j":["gesture","hand","OK","person gesturing OK","agree"]},"man-gesturing-ok":{"a":"Man Gesturing Ok","b":"1F646-200D-2642-FE0F","j":["gesture","hand","man","man gesturing OK","OK","men","boy","male","blue","human"]},"woman-gesturing-ok":{"a":"Woman Gesturing Ok","b":"1F646-200D-2640-FE0F","j":["gesture","hand","OK","woman","woman gesturing OK","women","girl","female","pink","human"]},"person-tipping-hand":{"a":"Person Tipping Hand","b":"1F481","j":["hand","help","information","sassy","tipping"]},"man-tipping-hand":{"a":"Man Tipping Hand","b":"1F481-200D-2642-FE0F","j":["man","sassy","tipping hand","male","boy","human","information"]},"woman-tipping-hand":{"a":"Woman Tipping Hand","b":"1F481-200D-2640-FE0F","j":["sassy","tipping hand","woman","female","girl","human","information"]},"person-raising-hand":{"a":"Person Raising Hand","b":"1F64B","j":["gesture","hand","happy","raised","question"]},"man-raising-hand":{"a":"Man Raising Hand","b":"1F64B-200D-2642-FE0F","j":["gesture","man","raising hand","male","boy"]},"woman-raising-hand":{"a":"Woman Raising Hand","b":"1F64B-200D-2640-FE0F","j":["gesture","raising hand","woman","female","girl"]},"deaf-person":{"a":"Deaf Person","b":"1F9CF","j":["accessibility","deaf","ear","hear"]},"deaf-man":{"a":"Deaf Man","b":"1F9CF-200D-2642-FE0F","j":["deaf","man","accessibility"]},"deaf-woman":{"a":"Deaf Woman","b":"1F9CF-200D-2640-FE0F","j":["deaf","woman","accessibility"]},"person-bowing":{"a":"Person Bowing","b":"1F647","j":["apology","bow","gesture","sorry","respectiful"]},"man-bowing":{"a":"Man Bowing","b":"1F647-200D-2642-FE0F","j":["apology","bowing","favor","gesture","man","sorry","male","boy"]},"woman-bowing":{"a":"Woman Bowing","b":"1F647-200D-2640-FE0F","j":["apology","bowing","favor","gesture","sorry","woman","female","girl"]},"person-facepalming":{"a":"Person Facepalming","b":"1F926","j":["disbelief","exasperation","face","palm","disappointed"]},"man-facepalming":{"a":"Man Facepalming","b":"1F926-200D-2642-FE0F","j":["disbelief","exasperation","facepalm","man","male","boy"]},"woman-facepalming":{"a":"Woman Facepalming","b":"1F926-200D-2640-FE0F","j":["disbelief","exasperation","facepalm","woman","female","girl"]},"person-shrugging":{"a":"Person Shrugging","b":"1F937","j":["doubt","ignorance","indifference","shrug","regardless"]},"man-shrugging":{"a":"Man Shrugging","b":"1F937-200D-2642-FE0F","j":["doubt","ignorance","indifference","man","shrug","male","boy","confused","indifferent"]},"woman-shrugging":{"a":"Woman Shrugging","b":"1F937-200D-2640-FE0F","j":["doubt","ignorance","indifference","shrug","woman","female","girl","confused","indifferent"]},"health-worker":{"a":"Health Worker","b":"1F9D1-200D-2695-FE0F","j":["doctor","healthcare","nurse","therapist","hospital"]},"man-health-worker":{"a":"Man Health Worker","b":"1F468-200D-2695-FE0F","j":["doctor","healthcare","man","nurse","therapist","human"]},"woman-health-worker":{"a":"Woman Health Worker","b":"1F469-200D-2695-FE0F","j":["doctor","healthcare","nurse","therapist","woman","human"]},"student":{"a":"Student","b":"1F9D1-200D-1F393","j":["graduate","learn"]},"man-student":{"a":"Man Student","b":"1F468-200D-1F393","j":["graduate","man","student","human"]},"woman-student":{"a":"Woman Student","b":"1F469-200D-1F393","j":["graduate","student","woman","human"]},"teacher":{"a":"Teacher","b":"1F9D1-200D-1F3EB","j":["instructor","professor"]},"man-teacher":{"a":"Man Teacher","b":"1F468-200D-1F3EB","j":["instructor","man","professor","teacher","human"]},"woman-teacher":{"a":"Woman Teacher","b":"1F469-200D-1F3EB","j":["instructor","professor","teacher","woman","human"]},"judge":{"a":"Judge","b":"1F9D1-200D-2696-FE0F","j":["justice","scales","law"]},"man-judge":{"a":"Man Judge","b":"1F468-200D-2696-FE0F","j":["judge","justice","man","scales","court","human"]},"woman-judge":{"a":"Woman Judge","b":"1F469-200D-2696-FE0F","j":["judge","justice","scales","woman","court","human"]},"farmer":{"a":"Farmer","b":"1F9D1-200D-1F33E","j":["gardener","rancher","crops"]},"man-farmer":{"a":"Man Farmer","b":"1F468-200D-1F33E","j":["farmer","gardener","man","rancher","human"]},"woman-farmer":{"a":"Woman Farmer","b":"1F469-200D-1F33E","j":["farmer","gardener","rancher","woman","human"]},"cook":{"a":"Cook","b":"1F9D1-200D-1F373","j":["chef","food","kitchen","culinary"]},"man-cook":{"a":"Man Cook","b":"1F468-200D-1F373","j":["chef","cook","man","human"]},"woman-cook":{"a":"Woman Cook","b":"1F469-200D-1F373","j":["chef","cook","woman","human"]},"mechanic":{"a":"Mechanic","b":"1F9D1-200D-1F527","j":["electrician","plumber","tradesperson","worker","technician"]},"man-mechanic":{"a":"Man Mechanic","b":"1F468-200D-1F527","j":["electrician","man","mechanic","plumber","tradesperson","human","wrench"]},"woman-mechanic":{"a":"Woman Mechanic","b":"1F469-200D-1F527","j":["electrician","mechanic","plumber","tradesperson","woman","human","wrench"]},"factory-worker":{"a":"Factory Worker","b":"1F9D1-200D-1F3ED","j":["assembly","factory","industrial","worker","labor"]},"man-factory-worker":{"a":"Man Factory Worker","b":"1F468-200D-1F3ED","j":["assembly","factory","industrial","man","worker","human"]},"woman-factory-worker":{"a":"Woman Factory Worker","b":"1F469-200D-1F3ED","j":["assembly","factory","industrial","woman","worker","human"]},"office-worker":{"a":"Office Worker","b":"1F9D1-200D-1F4BC","j":["architect","business","manager","white-collar"]},"man-office-worker":{"a":"Man Office Worker","b":"1F468-200D-1F4BC","j":["architect","business","man","manager","white-collar","human"]},"woman-office-worker":{"a":"Woman Office Worker","b":"1F469-200D-1F4BC","j":["architect","business","manager","white-collar","woman","human"]},"scientist":{"a":"Scientist","b":"1F9D1-200D-1F52C","j":["biologist","chemist","engineer","physicist","chemistry"]},"man-scientist":{"a":"Man Scientist","b":"1F468-200D-1F52C","j":["biologist","chemist","engineer","man","physicist","scientist","human"]},"woman-scientist":{"a":"Woman Scientist","b":"1F469-200D-1F52C","j":["biologist","chemist","engineer","physicist","scientist","woman","human"]},"technologist":{"a":"Technologist","b":"1F9D1-200D-1F4BB","j":["coder","developer","inventor","software","computer"]},"man-technologist":{"a":"Man Technologist","b":"1F468-200D-1F4BB","j":["coder","developer","inventor","man","software","technologist","engineer","programmer","human","laptop","computer"]},"woman-technologist":{"a":"Woman Technologist","b":"1F469-200D-1F4BB","j":["coder","developer","inventor","software","technologist","woman","engineer","programmer","human","laptop","computer"]},"singer":{"a":"Singer","b":"1F9D1-200D-1F3A4","j":["actor","entertainer","rock","star","song","artist","performer"]},"man-singer":{"a":"Man Singer","b":"1F468-200D-1F3A4","j":["actor","entertainer","man","rock","singer","star","rockstar","human"]},"woman-singer":{"a":"Woman Singer","b":"1F469-200D-1F3A4","j":["actor","entertainer","rock","singer","star","woman","rockstar","human"]},"artist":{"a":"Artist","b":"1F9D1-200D-1F3A8","j":["palette","painting","draw","creativity"]},"man-artist":{"a":"Man Artist","b":"1F468-200D-1F3A8","j":["artist","man","palette","painter","human"]},"woman-artist":{"a":"Woman Artist","b":"1F469-200D-1F3A8","j":["artist","palette","woman","painter","human"]},"pilot":{"a":"Pilot","b":"1F9D1-200D-2708-FE0F","j":["plane","fly","airplane"]},"man-pilot":{"a":"Man Pilot","b":"1F468-200D-2708-FE0F","j":["man","pilot","plane","aviator","human"]},"woman-pilot":{"a":"Woman Pilot","b":"1F469-200D-2708-FE0F","j":["pilot","plane","woman","aviator","human"]},"astronaut":{"a":"Astronaut","b":"1F9D1-200D-1F680","j":["rocket","outerspace"]},"man-astronaut":{"a":"Man Astronaut","b":"1F468-200D-1F680","j":["astronaut","man","rocket","space","human"]},"woman-astronaut":{"a":"Woman Astronaut","b":"1F469-200D-1F680","j":["astronaut","rocket","woman","space","human"]},"firefighter":{"a":"Firefighter","b":"1F9D1-200D-1F692","j":["firetruck","fire"]},"man-firefighter":{"a":"Man Firefighter","b":"1F468-200D-1F692","j":["firefighter","firetruck","man","fireman","human"]},"woman-firefighter":{"a":"Woman Firefighter","b":"1F469-200D-1F692","j":["firefighter","firetruck","woman","fireman","human"]},"police-officer":{"a":"Police Officer","b":"1F46E","j":["cop","officer","police"]},"man-police-officer":{"a":"Man Police Officer","b":"1F46E-200D-2642-FE0F","j":["cop","man","officer","police","law","legal","enforcement","arrest","911"]},"woman-police-officer":{"a":"Woman Police Officer","b":"1F46E-200D-2640-FE0F","j":["cop","officer","police","woman","law","legal","enforcement","arrest","911","female"]},"detective":{"a":"Detective","b":"1F575","j":["sleuth","spy","human"]},"man-detective":{"a":"Man Detective","b":"1F575-FE0F-200D-2642-FE0F","j":["detective","man","sleuth","spy","crime"]},"woman-detective":{"a":"Woman Detective","b":"1F575-FE0F-200D-2640-FE0F","j":["detective","sleuth","spy","woman","human","female"]},"guard":{"a":"Guard","b":"1F482","j":["protect"]},"man-guard":{"a":"Man Guard","b":"1F482-200D-2642-FE0F","j":["guard","man","uk","gb","british","male","guy","royal"]},"woman-guard":{"a":"Woman Guard","b":"1F482-200D-2640-FE0F","j":["guard","woman","uk","gb","british","female","royal"]},"ninja":{"a":"Ninja","b":"1F977","j":["fighter","hidden","stealth","ninjutsu","skills","japanese"]},"construction-worker":{"a":"Construction Worker","b":"1F477","j":["construction","hat","worker","labor","build"]},"man-construction-worker":{"a":"Man Construction Worker","b":"1F477-200D-2642-FE0F","j":["construction","man","worker","male","human","wip","guy","build","labor"]},"woman-construction-worker":{"a":"Woman Construction Worker","b":"1F477-200D-2640-FE0F","j":["construction","woman","worker","female","human","wip","build","labor"]},"person-with-crown":{"a":"⊛ Person with Crown","b":"1FAC5","j":["monarch","noble","regal","royalty"]},"prince":{"a":"Prince","b":"1F934","j":["boy","man","male","crown","royal","king"]},"princess":{"a":"Princess","b":"1F478","j":["fairy tale","fantasy","girl","woman","female","blond","crown","royal","queen"]},"person-wearing-turban":{"a":"Person Wearing Turban","b":"1F473","j":["turban","headdress"]},"man-wearing-turban":{"a":"Man Wearing Turban","b":"1F473-200D-2642-FE0F","j":["man","turban","male","indian","hinduism","arabs"]},"woman-wearing-turban":{"a":"Woman Wearing Turban","b":"1F473-200D-2640-FE0F","j":["turban","woman","female","indian","hinduism","arabs"]},"person-with-skullcap":{"a":"Person with Skullcap","b":"1F472","j":["cap","gua pi mao","hat","person","skullcap","man_with_skullcap","male","boy","chinese"]},"woman-with-headscarf":{"a":"Woman with Headscarf","b":"1F9D5","j":["headscarf","hijab","mantilla","tichel","bandana","head kerchief","female"]},"person-in-tuxedo":{"a":"Person in Tuxedo","b":"1F935","j":["groom","person","tuxedo","man_in_tuxedo","couple","marriage","wedding"]},"man-in-tuxedo":{"a":"Man in Tuxedo","b":"1F935-200D-2642-FE0F","j":["man","tuxedo","formal","fashion"]},"woman-in-tuxedo":{"a":"Woman in Tuxedo","b":"1F935-200D-2640-FE0F","j":["tuxedo","woman","formal","fashion"]},"person-with-veil":{"a":"Person with Veil","b":"1F470","j":["bride","person","veil","wedding","bride_with_veil","couple","marriage","woman"]},"man-with-veil":{"a":"Man with Veil","b":"1F470-200D-2642-FE0F","j":["man","veil","wedding","marriage"]},"woman-with-veil":{"a":"Woman with Veil","b":"1F470-200D-2640-FE0F","j":["veil","woman","wedding","marriage"]},"pregnant-woman":{"a":"Pregnant Woman","b":"1F930","j":["pregnant","woman","baby"]},"pregnant-man":{"a":"⊛ Pregnant Man","b":"1FAC3","j":["belly","bloated","full","pregnant"]},"pregnant-person":{"a":"⊛ Pregnant Person","b":"1FAC4","j":["belly","bloated","full","pregnant"]},"breastfeeding":{"a":"Breast-Feeding","b":"1F931","j":["baby","breast","breast-feeding","nursing","breast_feeding"]},"woman-feeding-baby":{"a":"Woman Feeding Baby","b":"1F469-200D-1F37C","j":["baby","feeding","nursing","woman","birth","food"]},"man-feeding-baby":{"a":"Man Feeding Baby","b":"1F468-200D-1F37C","j":["baby","feeding","man","nursing","birth","food"]},"person-feeding-baby":{"a":"Person Feeding Baby","b":"1F9D1-200D-1F37C","j":["baby","feeding","nursing","person","birth","food"]},"baby-angel":{"a":"Baby Angel","b":"1F47C","j":["angel","baby","face","fairy tale","fantasy","heaven","wings","halo"]},"santa-claus":{"a":"Santa Claus","b":"1F385","j":["celebration","Christmas","claus","father","santa","festival","man","male","xmas","father christmas"]},"mrs-claus":{"a":"Mrs. Claus","b":"1F936","j":["celebration","Christmas","claus","mother","Mrs.","woman","female","xmas","mother christmas"]},"mx-claus":{"a":"Mx Claus","b":"1F9D1-200D-1F384","j":["Claus, christmas","christmas"]},"superhero":{"a":"Superhero","b":"1F9B8","j":["good","hero","heroine","superpower","marvel"]},"man-superhero":{"a":"Man Superhero","b":"1F9B8-200D-2642-FE0F","j":["good","hero","man","superpower","male","superpowers"]},"woman-superhero":{"a":"Woman Superhero","b":"1F9B8-200D-2640-FE0F","j":["good","hero","heroine","superpower","woman","female","superpowers"]},"supervillain":{"a":"Supervillain","b":"1F9B9","j":["criminal","evil","superpower","villain","marvel"]},"man-supervillain":{"a":"Man Supervillain","b":"1F9B9-200D-2642-FE0F","j":["criminal","evil","man","superpower","villain","male","bad","hero","superpowers"]},"woman-supervillain":{"a":"Woman Supervillain","b":"1F9B9-200D-2640-FE0F","j":["criminal","evil","superpower","villain","woman","female","bad","heroine","superpowers"]},"mage":{"a":"Mage","b":"1F9D9","j":["sorcerer","sorceress","witch","wizard","magic"]},"man-mage":{"a":"Man Mage","b":"1F9D9-200D-2642-FE0F","j":["sorcerer","wizard","man","male","mage"]},"woman-mage":{"a":"Woman Mage","b":"1F9D9-200D-2640-FE0F","j":["sorceress","witch","woman","female","mage"]},"fairy":{"a":"Fairy","b":"1F9DA","j":["Oberon","Puck","Titania","wings","magical"]},"man-fairy":{"a":"Man Fairy","b":"1F9DA-200D-2642-FE0F","j":["Oberon","Puck","man","male"]},"woman-fairy":{"a":"Woman Fairy","b":"1F9DA-200D-2640-FE0F","j":["Titania","woman","female"]},"vampire":{"a":"Vampire","b":"1F9DB","j":["Dracula","undead","blood","twilight"]},"man-vampire":{"a":"Man Vampire","b":"1F9DB-200D-2642-FE0F","j":["Dracula","undead","man","male","dracula"]},"woman-vampire":{"a":"Woman Vampire","b":"1F9DB-200D-2640-FE0F","j":["undead","woman","female"]},"merperson":{"a":"Merperson","b":"1F9DC","j":["mermaid","merman","merwoman","sea"]},"merman":{"a":"Merman","b":"1F9DC-200D-2642-FE0F","j":["Triton","man","male","triton"]},"mermaid":{"a":"Mermaid","b":"1F9DC-200D-2640-FE0F","j":["merwoman","woman","female","ariel"]},"elf":{"a":"Elf","b":"1F9DD","j":["magical","LOTR style"]},"man-elf":{"a":"Man Elf","b":"1F9DD-200D-2642-FE0F","j":["magical","man","male"]},"woman-elf":{"a":"Woman Elf","b":"1F9DD-200D-2640-FE0F","j":["magical","woman","female"]},"genie":{"a":"Genie","b":"1F9DE","j":["djinn","(non-human color)","magical","wishes"]},"man-genie":{"a":"Man Genie","b":"1F9DE-200D-2642-FE0F","j":["djinn","man","male"]},"woman-genie":{"a":"Woman Genie","b":"1F9DE-200D-2640-FE0F","j":["djinn","woman","female"]},"zombie":{"a":"Zombie","b":"1F9DF","j":["undead","walking dead","(non-human color)","dead"]},"man-zombie":{"a":"Man Zombie","b":"1F9DF-200D-2642-FE0F","j":["undead","walking dead","man","male","dracula"]},"woman-zombie":{"a":"Woman Zombie","b":"1F9DF-200D-2640-FE0F","j":["undead","walking dead","woman","female"]},"troll":{"a":"⊛ Troll","b":"1F9CC","j":["fairy tale","fantasy","monster"]},"person-getting-massage":{"a":"Person Getting Massage","b":"1F486","j":["face","massage","salon","relax"]},"man-getting-massage":{"a":"Man Getting Massage","b":"1F486-200D-2642-FE0F","j":["face","man","massage","male","boy","head"]},"woman-getting-massage":{"a":"Woman Getting Massage","b":"1F486-200D-2640-FE0F","j":["face","massage","woman","female","girl","head"]},"person-getting-haircut":{"a":"Person Getting Haircut","b":"1F487","j":["barber","beauty","haircut","parlor","hairstyle"]},"man-getting-haircut":{"a":"Man Getting Haircut","b":"1F487-200D-2642-FE0F","j":["haircut","man","male","boy"]},"woman-getting-haircut":{"a":"Woman Getting Haircut","b":"1F487-200D-2640-FE0F","j":["haircut","woman","female","girl"]},"person-walking":{"a":"Person Walking","b":"1F6B6","j":["hike","walk","walking","move"]},"man-walking":{"a":"Man Walking","b":"1F6B6-200D-2642-FE0F","j":["hike","man","walk","human","feet","steps"]},"woman-walking":{"a":"Woman Walking","b":"1F6B6-200D-2640-FE0F","j":["hike","walk","woman","human","feet","steps","female"]},"person-standing":{"a":"Person Standing","b":"1F9CD","j":["stand","standing","still"]},"man-standing":{"a":"Man Standing","b":"1F9CD-200D-2642-FE0F","j":["man","standing","still"]},"woman-standing":{"a":"Woman Standing","b":"1F9CD-200D-2640-FE0F","j":["standing","woman","still"]},"person-kneeling":{"a":"Person Kneeling","b":"1F9CE","j":["kneel","kneeling","pray","respectful"]},"man-kneeling":{"a":"Man Kneeling","b":"1F9CE-200D-2642-FE0F","j":["kneeling","man","pray","respectful"]},"woman-kneeling":{"a":"Woman Kneeling","b":"1F9CE-200D-2640-FE0F","j":["kneeling","woman","respectful","pray"]},"person-with-white-cane":{"a":"Person with White Cane","b":"1F9D1-200D-1F9AF","j":["accessibility","blind","person_with_probing_cane"]},"man-with-white-cane":{"a":"Man with White Cane","b":"1F468-200D-1F9AF","j":["accessibility","blind","man","man_with_probing_cane"]},"woman-with-white-cane":{"a":"Woman with White Cane","b":"1F469-200D-1F9AF","j":["accessibility","blind","woman","woman_with_probing_cane"]},"person-in-motorized-wheelchair":{"a":"Person in Motorized Wheelchair","b":"1F9D1-200D-1F9BC","j":["accessibility","wheelchair","disability"]},"man-in-motorized-wheelchair":{"a":"Man in Motorized Wheelchair","b":"1F468-200D-1F9BC","j":["accessibility","man","wheelchair","disability"]},"woman-in-motorized-wheelchair":{"a":"Woman in Motorized Wheelchair","b":"1F469-200D-1F9BC","j":["accessibility","wheelchair","woman","disability"]},"person-in-manual-wheelchair":{"a":"Person in Manual Wheelchair","b":"1F9D1-200D-1F9BD","j":["accessibility","wheelchair","disability"]},"man-in-manual-wheelchair":{"a":"Man in Manual Wheelchair","b":"1F468-200D-1F9BD","j":["accessibility","man","wheelchair","disability"]},"woman-in-manual-wheelchair":{"a":"Woman in Manual Wheelchair","b":"1F469-200D-1F9BD","j":["accessibility","wheelchair","woman","disability"]},"person-running":{"a":"Person Running","b":"1F3C3","j":["marathon","running","move"]},"man-running":{"a":"Man Running","b":"1F3C3-200D-2642-FE0F","j":["man","marathon","racing","running","walking","exercise","race"]},"woman-running":{"a":"Woman Running","b":"1F3C3-200D-2640-FE0F","j":["marathon","racing","running","woman","walking","exercise","race","female"]},"woman-dancing":{"a":"Woman Dancing","b":"1F483","j":["dance","dancing","woman","female","girl","fun"]},"man-dancing":{"a":"Man Dancing","b":"1F57A","j":["dance","dancing","man","male","boy","fun","dancer"]},"person-in-suit-levitating":{"a":"Person in Suit Levitating","b":"1F574","j":["business","person","suit","man_in_suit_levitating","levitate","hover","jump"]},"people-with-bunny-ears":{"a":"People with Bunny Ears","b":"1F46F","j":["bunny ear","dancer","partying","perform","costume"]},"men-with-bunny-ears":{"a":"Men with Bunny Ears","b":"1F46F-200D-2642-FE0F","j":["bunny ear","dancer","men","partying","male","bunny","boys"]},"women-with-bunny-ears":{"a":"Women with Bunny Ears","b":"1F46F-200D-2640-FE0F","j":["bunny ear","dancer","partying","women","female","bunny","girls"]},"person-in-steamy-room":{"a":"Person in Steamy Room","b":"1F9D6","j":["sauna","steam room","hamam","steambath","relax","spa"]},"man-in-steamy-room":{"a":"Man in Steamy Room","b":"1F9D6-200D-2642-FE0F","j":["sauna","steam room","male","man","spa","steamroom"]},"woman-in-steamy-room":{"a":"Woman in Steamy Room","b":"1F9D6-200D-2640-FE0F","j":["sauna","steam room","female","woman","spa","steamroom"]},"person-climbing":{"a":"Person Climbing","b":"1F9D7","j":["climber","sport"]},"man-climbing":{"a":"Man Climbing","b":"1F9D7-200D-2642-FE0F","j":["climber","sports","hobby","man","male","rock"]},"woman-climbing":{"a":"Woman Climbing","b":"1F9D7-200D-2640-FE0F","j":["climber","sports","hobby","woman","female","rock"]},"person-fencing":{"a":"Person Fencing","b":"1F93A","j":["fencer","fencing","sword","sports"]},"horse-racing":{"a":"Horse Racing","b":"1F3C7","j":["horse","jockey","racehorse","racing","animal","betting","competition","gambling","luck"]},"skier":{"a":"Skier","b":"26F7","j":["ski","snow","sports","winter"]},"snowboarder":{"a":"Snowboarder","b":"1F3C2","j":["ski","snow","snowboard","sports","winter"]},"person-golfing":{"a":"Person Golfing","b":"1F3CC","j":["ball","golf","sports","business"]},"man-golfing":{"a":"Man Golfing","b":"1F3CC-FE0F-200D-2642-FE0F","j":["golf","man","sport"]},"woman-golfing":{"a":"Woman Golfing","b":"1F3CC-FE0F-200D-2640-FE0F","j":["golf","woman","sports","business","female"]},"person-surfing":{"a":"Person Surfing","b":"1F3C4","j":["surfing","sport","sea"]},"man-surfing":{"a":"Man Surfing","b":"1F3C4-200D-2642-FE0F","j":["man","surfing","sports","ocean","sea","summer","beach"]},"woman-surfing":{"a":"Woman Surfing","b":"1F3C4-200D-2640-FE0F","j":["surfing","woman","sports","ocean","sea","summer","beach","female"]},"person-rowing-boat":{"a":"Person Rowing Boat","b":"1F6A3","j":["boat","rowboat","sport","move"]},"man-rowing-boat":{"a":"Man Rowing Boat","b":"1F6A3-200D-2642-FE0F","j":["boat","man","rowboat","sports","hobby","water","ship"]},"woman-rowing-boat":{"a":"Woman Rowing Boat","b":"1F6A3-200D-2640-FE0F","j":["boat","rowboat","woman","sports","hobby","water","ship","female"]},"person-swimming":{"a":"Person Swimming","b":"1F3CA","j":["swim","sport","pool"]},"man-swimming":{"a":"Man Swimming","b":"1F3CA-200D-2642-FE0F","j":["man","swim","sports","exercise","human","athlete","water","summer"]},"woman-swimming":{"a":"Woman Swimming","b":"1F3CA-200D-2640-FE0F","j":["swim","woman","sports","exercise","human","athlete","water","summer","female"]},"person-bouncing-ball":{"a":"Person Bouncing Ball","b":"26F9","j":["ball","sports","human"]},"man-bouncing-ball":{"a":"Man Bouncing Ball","b":"26F9-FE0F-200D-2642-FE0F","j":["ball","man","sport"]},"woman-bouncing-ball":{"a":"Woman Bouncing Ball","b":"26F9-FE0F-200D-2640-FE0F","j":["ball","woman","sports","human","female"]},"person-lifting-weights":{"a":"Person Lifting Weights","b":"1F3CB","j":["lifter","weight","sports","training","exercise"]},"man-lifting-weights":{"a":"Man Lifting Weights","b":"1F3CB-FE0F-200D-2642-FE0F","j":["man","weight lifter","sport"]},"woman-lifting-weights":{"a":"Woman Lifting Weights","b":"1F3CB-FE0F-200D-2640-FE0F","j":["weight lifter","woman","sports","training","exercise","female"]},"person-biking":{"a":"Person Biking","b":"1F6B4","j":["bicycle","biking","cyclist","sport","move"]},"man-biking":{"a":"Man Biking","b":"1F6B4-200D-2642-FE0F","j":["bicycle","biking","cyclist","man","sports","bike","exercise","hipster"]},"woman-biking":{"a":"Woman Biking","b":"1F6B4-200D-2640-FE0F","j":["bicycle","biking","cyclist","woman","sports","bike","exercise","hipster","female"]},"person-mountain-biking":{"a":"Person Mountain Biking","b":"1F6B5","j":["bicycle","bicyclist","bike","cyclist","mountain","sport","move"]},"man-mountain-biking":{"a":"Man Mountain Biking","b":"1F6B5-200D-2642-FE0F","j":["bicycle","bike","cyclist","man","mountain","transportation","sports","human","race"]},"woman-mountain-biking":{"a":"Woman Mountain Biking","b":"1F6B5-200D-2640-FE0F","j":["bicycle","bike","biking","cyclist","mountain","woman","transportation","sports","human","race","female"]},"person-cartwheeling":{"a":"Person Cartwheeling","b":"1F938","j":["cartwheel","gymnastics","sport","gymnastic"]},"man-cartwheeling":{"a":"Man Cartwheeling","b":"1F938-200D-2642-FE0F","j":["cartwheel","gymnastics","man"]},"woman-cartwheeling":{"a":"Woman Cartwheeling","b":"1F938-200D-2640-FE0F","j":["cartwheel","gymnastics","woman"]},"people-wrestling":{"a":"People Wrestling","b":"1F93C","j":["wrestle","wrestler","sport"]},"men-wrestling":{"a":"Men Wrestling","b":"1F93C-200D-2642-FE0F","j":["men","wrestle","sports","wrestlers"]},"women-wrestling":{"a":"Women Wrestling","b":"1F93C-200D-2640-FE0F","j":["women","wrestle","sports","wrestlers"]},"person-playing-water-polo":{"a":"Person Playing Water Polo","b":"1F93D","j":["polo","water","sport"]},"man-playing-water-polo":{"a":"Man Playing Water Polo","b":"1F93D-200D-2642-FE0F","j":["man","water polo","sports","pool"]},"woman-playing-water-polo":{"a":"Woman Playing Water Polo","b":"1F93D-200D-2640-FE0F","j":["water polo","woman","sports","pool"]},"person-playing-handball":{"a":"Person Playing Handball","b":"1F93E","j":["ball","handball","sport"]},"man-playing-handball":{"a":"Man Playing Handball","b":"1F93E-200D-2642-FE0F","j":["handball","man","sports"]},"woman-playing-handball":{"a":"Woman Playing Handball","b":"1F93E-200D-2640-FE0F","j":["handball","woman","sports"]},"person-juggling":{"a":"Person Juggling","b":"1F939","j":["balance","juggle","multitask","skill","performance"]},"man-juggling":{"a":"Man Juggling","b":"1F939-200D-2642-FE0F","j":["juggling","man","multitask","juggle","balance","skill"]},"woman-juggling":{"a":"Woman Juggling","b":"1F939-200D-2640-FE0F","j":["juggling","multitask","woman","juggle","balance","skill"]},"person-in-lotus-position":{"a":"Person in Lotus Position","b":"1F9D8","j":["meditation","yoga","serenity","meditate"]},"man-in-lotus-position":{"a":"Man in Lotus Position","b":"1F9D8-200D-2642-FE0F","j":["meditation","yoga","man","male","serenity","zen","mindfulness"]},"woman-in-lotus-position":{"a":"Woman in Lotus Position","b":"1F9D8-200D-2640-FE0F","j":["meditation","yoga","woman","female","serenity","zen","mindfulness"]},"person-taking-bath":{"a":"Person Taking Bath","b":"1F6C0","j":["bath","bathtub","clean","shower","bathroom"]},"person-in-bed":{"a":"Person in Bed","b":"1F6CC","j":["hotel","sleep","bed","rest"]},"people-holding-hands":{"a":"People Holding Hands","b":"1F9D1-200D-1F91D-200D-1F9D1","j":["couple","hand","hold","holding hands","person","friendship"]},"women-holding-hands":{"a":"Women Holding Hands","b":"1F46D","j":["couple","hand","holding hands","women","pair","friendship","love","like","female","people","human"]},"woman-and-man-holding-hands":{"a":"Woman and Man Holding Hands","b":"1F46B","j":["couple","hand","hold","holding hands","man","woman","pair","people","human","love","date","dating","like","affection","valentines","marriage"]},"men-holding-hands":{"a":"Men Holding Hands","b":"1F46C","j":["couple","Gemini","holding hands","man","men","twins","zodiac","pair","love","like","bromance","friendship","people","human"]},"kiss":{"a":"Kiss","b":"1F48F","j":["couple","pair","valentines","love","like","dating","marriage"]},"kiss-woman-man":{"a":"Kiss: Woman, Man","b":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F468","j":["couple","kiss","man","woman","love"]},"kiss-man-man":{"a":"Kiss: Man, Man","b":"1F468-200D-2764-FE0F-200D-1F48B-200D-1F468","j":["couple","kiss","man","pair","valentines","love","like","dating","marriage"]},"kiss-woman-woman":{"a":"Kiss: Woman, Woman","b":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F469","j":["couple","kiss","woman","pair","valentines","love","like","dating","marriage"]},"couple-with-heart":{"a":"Couple with Heart","b":"1F491","j":["couple","love","pair","like","affection","human","dating","valentines","marriage"]},"couple-with-heart-woman-man":{"a":"Couple with Heart: Woman, Man","b":"1F469-200D-2764-FE0F-200D-1F468","j":["couple","couple with heart","love","man","woman"]},"couple-with-heart-man-man":{"a":"Couple with Heart: Man, Man","b":"1F468-200D-2764-FE0F-200D-1F468","j":["couple","couple with heart","love","man","pair","like","affection","human","dating","valentines","marriage"]},"couple-with-heart-woman-woman":{"a":"Couple with Heart: Woman, Woman","b":"1F469-200D-2764-FE0F-200D-1F469","j":["couple","couple with heart","love","woman","pair","like","affection","human","dating","valentines","marriage"]},"family":{"a":"Family","b":"1F46A","j":["home","parents","child","mom","dad","father","mother","people","human"]},"family-man-woman-boy":{"a":"Family: Man, Woman, Boy","b":"1F468-200D-1F469-200D-1F466","j":["boy","family","man","woman","love"]},"family-man-woman-girl":{"a":"Family: Man, Woman, Girl","b":"1F468-200D-1F469-200D-1F467","j":["family","girl","man","woman","home","parents","people","human","child"]},"family-man-woman-girl-boy":{"a":"Family: Man, Woman, Girl, Boy","b":"1F468-200D-1F469-200D-1F467-200D-1F466","j":["boy","family","girl","man","woman","home","parents","people","human","children"]},"family-man-woman-boy-boy":{"a":"Family: Man, Woman, Boy, Boy","b":"1F468-200D-1F469-200D-1F466-200D-1F466","j":["boy","family","man","woman","home","parents","people","human","children"]},"family-man-woman-girl-girl":{"a":"Family: Man, Woman, Girl, Girl","b":"1F468-200D-1F469-200D-1F467-200D-1F467","j":["family","girl","man","woman","home","parents","people","human","children"]},"family-man-man-boy":{"a":"Family: Man, Man, Boy","b":"1F468-200D-1F468-200D-1F466","j":["boy","family","man","home","parents","people","human","children"]},"family-man-man-girl":{"a":"Family: Man, Man, Girl","b":"1F468-200D-1F468-200D-1F467","j":["family","girl","man","home","parents","people","human","children"]},"family-man-man-girl-boy":{"a":"Family: Man, Man, Girl, Boy","b":"1F468-200D-1F468-200D-1F467-200D-1F466","j":["boy","family","girl","man","home","parents","people","human","children"]},"family-man-man-boy-boy":{"a":"Family: Man, Man, Boy, Boy","b":"1F468-200D-1F468-200D-1F466-200D-1F466","j":["boy","family","man","home","parents","people","human","children"]},"family-man-man-girl-girl":{"a":"Family: Man, Man, Girl, Girl","b":"1F468-200D-1F468-200D-1F467-200D-1F467","j":["family","girl","man","home","parents","people","human","children"]},"family-woman-woman-boy":{"a":"Family: Woman, Woman, Boy","b":"1F469-200D-1F469-200D-1F466","j":["boy","family","woman","home","parents","people","human","children"]},"family-woman-woman-girl":{"a":"Family: Woman, Woman, Girl","b":"1F469-200D-1F469-200D-1F467","j":["family","girl","woman","home","parents","people","human","children"]},"family-woman-woman-girl-boy":{"a":"Family: Woman, Woman, Girl, Boy","b":"1F469-200D-1F469-200D-1F467-200D-1F466","j":["boy","family","girl","woman","home","parents","people","human","children"]},"family-woman-woman-boy-boy":{"a":"Family: Woman, Woman, Boy, Boy","b":"1F469-200D-1F469-200D-1F466-200D-1F466","j":["boy","family","woman","home","parents","people","human","children"]},"family-woman-woman-girl-girl":{"a":"Family: Woman, Woman, Girl, Girl","b":"1F469-200D-1F469-200D-1F467-200D-1F467","j":["family","girl","woman","home","parents","people","human","children"]},"family-man-boy":{"a":"Family: Man, Boy","b":"1F468-200D-1F466","j":["boy","family","man","home","parent","people","human","child"]},"family-man-boy-boy":{"a":"Family: Man, Boy, Boy","b":"1F468-200D-1F466-200D-1F466","j":["boy","family","man","home","parent","people","human","children"]},"family-man-girl":{"a":"Family: Man, Girl","b":"1F468-200D-1F467","j":["family","girl","man","home","parent","people","human","child"]},"family-man-girl-boy":{"a":"Family: Man, Girl, Boy","b":"1F468-200D-1F467-200D-1F466","j":["boy","family","girl","man","home","parent","people","human","children"]},"family-man-girl-girl":{"a":"Family: Man, Girl, Girl","b":"1F468-200D-1F467-200D-1F467","j":["family","girl","man","home","parent","people","human","children"]},"family-woman-boy":{"a":"Family: Woman, Boy","b":"1F469-200D-1F466","j":["boy","family","woman","home","parent","people","human","child"]},"family-woman-boy-boy":{"a":"Family: Woman, Boy, Boy","b":"1F469-200D-1F466-200D-1F466","j":["boy","family","woman","home","parent","people","human","children"]},"family-woman-girl":{"a":"Family: Woman, Girl","b":"1F469-200D-1F467","j":["family","girl","woman","home","parent","people","human","child"]},"family-woman-girl-boy":{"a":"Family: Woman, Girl, Boy","b":"1F469-200D-1F467-200D-1F466","j":["boy","family","girl","woman","home","parent","people","human","children"]},"family-woman-girl-girl":{"a":"Family: Woman, Girl, Girl","b":"1F469-200D-1F467-200D-1F467","j":["family","girl","woman","home","parent","people","human","children"]},"speaking-head":{"a":"Speaking Head","b":"1F5E3","j":["face","head","silhouette","speak","speaking","user","person","human","sing","say","talk"]},"bust-in-silhouette":{"a":"Bust in Silhouette","b":"1F464","j":["bust","silhouette","user","person","human"]},"busts-in-silhouette":{"a":"Busts in Silhouette","b":"1F465","j":["bust","silhouette","user","person","human","group","team"]},"people-hugging":{"a":"People Hugging","b":"1FAC2","j":["goodbye","hello","hug","thanks","care"]},"footprints":{"a":"Footprints","b":"1F463","j":["clothing","footprint","print","feet","tracking","walking","beach"]},"red-hair":{"a":"Red Hair","b":"1F9B0","j":["ginger","red hair","redhead"]},"curly-hair":{"a":"Curly Hair","b":"1F9B1","j":["afro","curly","curly hair","ringlets"]},"white-hair":{"a":"White Hair","b":"1F9B3","j":["gray","hair","old","white"]},"bald":{"a":"Bald","b":"1F9B2","j":["bald","chemotherapy","hairless","no hair","shaven"]},"monkey-face":{"a":"Monkey Face","b":"1F435","j":["face","monkey","animal","nature","circus"]},"monkey":{"a":"Monkey","b":"1F412","j":["animal","nature","banana","circus"]},"gorilla":{"a":"Gorilla","b":"1F98D","j":["animal","nature","circus"]},"orangutan":{"a":"Orangutan","b":"1F9A7","j":["ape","animal"]},"dog-face":{"a":"Dog Face","b":"1F436","j":["dog","face","pet","animal","friend","nature","woof","puppy","faithful"]},"dog":{"a":"Dog","b":"1F415","j":["pet","animal","nature","friend","doge","faithful"]},"guide-dog":{"a":"Guide Dog","b":"1F9AE","j":["accessibility","blind","guide","animal"]},"service-dog":{"a":"Service Dog","b":"1F415-200D-1F9BA","j":["accessibility","assistance","dog","service","blind","animal"]},"poodle":{"a":"Poodle","b":"1F429","j":["dog","animal","101","nature","pet"]},"wolf":{"a":"Wolf","b":"1F43A","j":["face","animal","nature","wild"]},"fox":{"a":"Fox","b":"1F98A","j":["face","animal","nature"]},"raccoon":{"a":"Raccoon","b":"1F99D","j":["curious","sly","animal","nature"]},"cat-face":{"a":"Cat Face","b":"1F431","j":["cat","face","pet","animal","meow","nature","kitten"]},"cat":{"a":"Cat","b":"1F408","j":["pet","animal","meow","cats"]},"black-cat":{"a":"Black Cat","b":"1F408-200D-2B1B","j":["black","cat","unlucky","superstition","luck"]},"lion":{"a":"Lion","b":"1F981","j":["face","Leo","zodiac","animal","nature"]},"tiger-face":{"a":"Tiger Face","b":"1F42F","j":["face","tiger","animal","cat","danger","wild","nature","roar"]},"tiger":{"a":"Tiger","b":"1F405","j":["animal","nature","roar"]},"leopard":{"a":"Leopard","b":"1F406","j":["animal","nature"]},"horse-face":{"a":"Horse Face","b":"1F434","j":["face","horse","animal","brown","nature"]},"horse":{"a":"Horse","b":"1F40E","j":["equestrian","racehorse","racing","animal","gamble","luck"]},"unicorn":{"a":"Unicorn","b":"1F984","j":["face","animal","nature","mystical"]},"zebra":{"a":"Zebra","b":"1F993","j":["stripe","animal","nature","stripes","safari"]},"deer":{"a":"Deer","b":"1F98C","j":["animal","nature","horns","venison"]},"bison":{"a":"Bison","b":"1F9AC","j":["buffalo","herd","wisent","ox"]},"cow-face":{"a":"Cow Face","b":"1F42E","j":["cow","face","beef","ox","animal","nature","moo","milk"]},"ox":{"a":"Ox","b":"1F402","j":["bull","Taurus","zodiac","animal","cow","beef"]},"water-buffalo":{"a":"Water Buffalo","b":"1F403","j":["buffalo","water","animal","nature","ox","cow"]},"cow":{"a":"Cow","b":"1F404","j":["beef","ox","animal","nature","moo","milk"]},"pig-face":{"a":"Pig Face","b":"1F437","j":["face","pig","animal","oink","nature"]},"pig":{"a":"Pig","b":"1F416","j":["sow","animal","nature"]},"boar":{"a":"Boar","b":"1F417","j":["pig","animal","nature"]},"pig-nose":{"a":"Pig Nose","b":"1F43D","j":["face","nose","pig","animal","oink"]},"ram":{"a":"Ram","b":"1F40F","j":["Aries","male","sheep","zodiac","animal","nature"]},"ewe":{"a":"Ewe","b":"1F411","j":["female","sheep","animal","nature","wool","shipit"]},"goat":{"a":"Goat","b":"1F410","j":["Capricorn","zodiac","animal","nature"]},"camel":{"a":"Camel","b":"1F42A","j":["dromedary","hump","animal","hot","desert"]},"twohump-camel":{"a":"Two-Hump Camel","b":"1F42B","j":["bactrian","camel","hump","two-hump camel","two_hump_camel","animal","nature","hot","desert"]},"llama":{"a":"Llama","b":"1F999","j":["alpaca","guanaco","vicuña","wool","animal","nature"]},"giraffe":{"a":"Giraffe","b":"1F992","j":["spots","animal","nature","safari"]},"elephant":{"a":"Elephant","b":"1F418","j":["animal","nature","nose","th","circus"]},"mammoth":{"a":"Mammoth","b":"1F9A3","j":["extinction","large","tusk","woolly","elephant","tusks"]},"rhinoceros":{"a":"Rhinoceros","b":"1F98F","j":["animal","nature","horn"]},"hippopotamus":{"a":"Hippopotamus","b":"1F99B","j":["hippo","animal","nature"]},"mouse-face":{"a":"Mouse Face","b":"1F42D","j":["face","mouse","animal","nature","cheese_wedge","rodent"]},"mouse":{"a":"Mouse","b":"1F401","j":["animal","nature","rodent"]},"rat":{"a":"Rat","b":"1F400","j":["animal","mouse","rodent"]},"hamster":{"a":"Hamster","b":"1F439","j":["face","pet","animal","nature"]},"rabbit-face":{"a":"Rabbit Face","b":"1F430","j":["bunny","face","pet","rabbit","animal","nature","spring","magic"]},"rabbit":{"a":"Rabbit","b":"1F407","j":["bunny","pet","animal","nature","magic","spring"]},"chipmunk":{"a":"Chipmunk","b":"1F43F","j":["squirrel","animal","nature","rodent"]},"beaver":{"a":"Beaver","b":"1F9AB","j":["dam","animal","rodent"]},"hedgehog":{"a":"Hedgehog","b":"1F994","j":["spiny","animal","nature"]},"bat":{"a":"Bat","b":"1F987","j":["vampire","animal","nature","blind"]},"bear":{"a":"Bear","b":"1F43B","j":["face","animal","nature","wild"]},"polar-bear":{"a":"Polar Bear","b":"1F43B-200D-2744-FE0F","j":["arctic","bear","white","animal"]},"koala":{"a":"Koala","b":"1F428","j":["face","marsupial","animal","nature"]},"panda":{"a":"Panda","b":"1F43C","j":["face","animal","nature"]},"sloth":{"a":"Sloth","b":"1F9A5","j":["lazy","slow","animal"]},"otter":{"a":"Otter","b":"1F9A6","j":["fishing","playful","animal"]},"skunk":{"a":"Skunk","b":"1F9A8","j":["stink","animal"]},"kangaroo":{"a":"Kangaroo","b":"1F998","j":["Australia","joey","jump","marsupial","animal","nature","australia","hop"]},"badger":{"a":"Badger","b":"1F9A1","j":["honey badger","pester","animal","nature","honey"]},"paw-prints":{"a":"Paw Prints","b":"1F43E","j":["feet","paw","print","animal","tracking","footprints","dog","cat","pet"]},"turkey":{"a":"Turkey","b":"1F983","j":["bird","animal"]},"chicken":{"a":"Chicken","b":"1F414","j":["bird","animal","cluck","nature"]},"rooster":{"a":"Rooster","b":"1F413","j":["bird","animal","nature","chicken"]},"hatching-chick":{"a":"Hatching Chick","b":"1F423","j":["baby","bird","chick","hatching","animal","chicken","egg","born"]},"baby-chick":{"a":"Baby Chick","b":"1F424","j":["baby","bird","chick","animal","chicken"]},"frontfacing-baby-chick":{"a":"Front-Facing Baby Chick","b":"1F425","j":["baby","bird","chick","front-facing baby chick","front_facing_baby_chick","animal","chicken"]},"bird":{"a":"Bird","b":"1F426","j":["animal","nature","fly","tweet","spring"]},"penguin":{"a":"Penguin","b":"1F427","j":["bird","animal","nature"]},"dove":{"a":"Dove","b":"1F54A","j":["bird","fly","peace","animal"]},"eagle":{"a":"Eagle","b":"1F985","j":["bird","animal","nature"]},"duck":{"a":"Duck","b":"1F986","j":["bird","animal","nature","mallard"]},"swan":{"a":"Swan","b":"1F9A2","j":["bird","cygnet","ugly duckling","animal","nature"]},"owl":{"a":"Owl","b":"1F989","j":["bird","wise","animal","nature","hoot"]},"dodo":{"a":"Dodo","b":"1F9A4","j":["extinction","large","Mauritius","animal","bird"]},"feather":{"a":"Feather","b":"1FAB6","j":["bird","flight","light","plumage","fly"]},"flamingo":{"a":"Flamingo","b":"1F9A9","j":["flamboyant","tropical","animal"]},"peacock":{"a":"Peacock","b":"1F99A","j":["bird","ostentatious","peahen","proud","animal","nature"]},"parrot":{"a":"Parrot","b":"1F99C","j":["bird","pirate","talk","animal","nature"]},"frog":{"a":"Frog","b":"1F438","j":["face","animal","nature","croak","toad"]},"crocodile":{"a":"Crocodile","b":"1F40A","j":["animal","nature","reptile","lizard","alligator"]},"turtle":{"a":"Turtle","b":"1F422","j":["terrapin","tortoise","animal","slow","nature"]},"lizard":{"a":"Lizard","b":"1F98E","j":["reptile","animal","nature"]},"snake":{"a":"Snake","b":"1F40D","j":["bearer","Ophiuchus","serpent","zodiac","animal","evil","nature","hiss","python"]},"dragon-face":{"a":"Dragon Face","b":"1F432","j":["dragon","face","fairy tale","animal","myth","nature","chinese","green"]},"dragon":{"a":"Dragon","b":"1F409","j":["fairy tale","animal","myth","nature","chinese","green"]},"sauropod":{"a":"Sauropod","b":"1F995","j":["brachiosaurus","brontosaurus","diplodocus","animal","nature","dinosaur","extinct"]},"trex":{"a":"T-Rex","b":"1F996","j":["Tyrannosaurus Rex","t_rex","animal","nature","dinosaur","tyrannosaurus","extinct"]},"spouting-whale":{"a":"Spouting Whale","b":"1F433","j":["face","spouting","whale","animal","nature","sea","ocean"]},"whale":{"a":"Whale","b":"1F40B","j":["animal","nature","sea","ocean"]},"dolphin":{"a":"Dolphin","b":"1F42C","j":["flipper","animal","nature","fish","sea","ocean","fins","beach"]},"seal":{"a":"Seal","b":"1F9AD","j":["sea lion","animal","creature","sea"]},"fish":{"a":"Fish","b":"1F41F","j":["Pisces","zodiac","animal","food","nature"]},"tropical-fish":{"a":"Tropical Fish","b":"1F420","j":["fish","tropical","animal","swim","ocean","beach","nemo"]},"blowfish":{"a":"Blowfish","b":"1F421","j":["fish","animal","nature","food","sea","ocean"]},"shark":{"a":"Shark","b":"1F988","j":["fish","animal","nature","sea","ocean","jaws","fins","beach"]},"octopus":{"a":"Octopus","b":"1F419","j":["animal","creature","ocean","sea","nature","beach"]},"spiral-shell":{"a":"Spiral Shell","b":"1F41A","j":["shell","spiral","nature","sea","beach"]},"coral":{"a":"⊛ Coral","b":"1FAB8","j":["ocean","reef"]},"snail":{"a":"Snail","b":"1F40C","j":["slow","animal","shell"]},"butterfly":{"a":"Butterfly","b":"1F98B","j":["insect","pretty","animal","nature","caterpillar"]},"bug":{"a":"Bug","b":"1F41B","j":["insect","animal","nature","worm"]},"ant":{"a":"Ant","b":"1F41C","j":["insect","animal","nature","bug"]},"honeybee":{"a":"Honeybee","b":"1F41D","j":["bee","insect","animal","nature","bug","spring","honey"]},"beetle":{"a":"Beetle","b":"1FAB2","j":["bug","insect"]},"lady-beetle":{"a":"Lady Beetle","b":"1F41E","j":["beetle","insect","ladybird","ladybug","animal","nature"]},"cricket":{"a":"Cricket","b":"1F997","j":["grasshopper","Orthoptera","animal","chirp"]},"cockroach":{"a":"Cockroach","b":"1FAB3","j":["insect","pest","roach","pests"]},"spider":{"a":"Spider","b":"1F577","j":["insect","animal","arachnid"]},"spider-web":{"a":"Spider Web","b":"1F578","j":["spider","web","animal","insect","arachnid","silk"]},"scorpion":{"a":"Scorpion","b":"1F982","j":["scorpio","Scorpio","zodiac","animal","arachnid"]},"mosquito":{"a":"Mosquito","b":"1F99F","j":["disease","fever","malaria","pest","virus","animal","nature","insect"]},"fly":{"a":"Fly","b":"1FAB0","j":["disease","maggot","pest","rotting","insect"]},"worm":{"a":"Worm","b":"1FAB1","j":["annelid","earthworm","parasite","animal"]},"microbe":{"a":"Microbe","b":"1F9A0","j":["amoeba","bacteria","virus","germs"]},"bouquet":{"a":"Bouquet","b":"1F490","j":["flower","flowers","nature","spring"]},"cherry-blossom":{"a":"Cherry Blossom","b":"1F338","j":["blossom","cherry","flower","nature","plant","spring"]},"white-flower":{"a":"White Flower","b":"1F4AE","j":["flower","japanese","spring"]},"lotus":{"a":"⊛ Lotus","b":"1FAB7","j":["Buddhism","flower","Hinduism","India","purity","Vietnam"]},"rosette":{"a":"Rosette","b":"1F3F5","j":["plant","flower","decoration","military"]},"rose":{"a":"Rose","b":"1F339","j":["flower","flowers","valentines","love","spring"]},"wilted-flower":{"a":"Wilted Flower","b":"1F940","j":["flower","wilted","plant","nature"]},"hibiscus":{"a":"Hibiscus","b":"1F33A","j":["flower","plant","vegetable","flowers","beach"]},"sunflower":{"a":"Sunflower","b":"1F33B","j":["flower","sun","nature","plant","fall"]},"blossom":{"a":"Blossom","b":"1F33C","j":["flower","nature","flowers","yellow"]},"tulip":{"a":"Tulip","b":"1F337","j":["flower","flowers","plant","nature","summer","spring"]},"seedling":{"a":"Seedling","b":"1F331","j":["young","plant","nature","grass","lawn","spring"]},"potted-plant":{"a":"Potted Plant","b":"1FAB4","j":["boring","grow","house","nurturing","plant","useless","greenery"]},"evergreen-tree":{"a":"Evergreen Tree","b":"1F332","j":["tree","plant","nature"]},"deciduous-tree":{"a":"Deciduous Tree","b":"1F333","j":["deciduous","shedding","tree","plant","nature"]},"palm-tree":{"a":"Palm Tree","b":"1F334","j":["palm","tree","plant","vegetable","nature","summer","beach","mojito","tropical"]},"cactus":{"a":"Cactus","b":"1F335","j":["plant","vegetable","nature"]},"sheaf-of-rice":{"a":"Sheaf of Rice","b":"1F33E","j":["ear","grain","rice","nature","plant"]},"herb":{"a":"Herb","b":"1F33F","j":["leaf","vegetable","plant","medicine","weed","grass","lawn"]},"shamrock":{"a":"Shamrock","b":"2618","j":["plant","vegetable","nature","irish","clover"]},"four-leaf-clover":{"a":"Four Leaf Clover","b":"1F340","j":["4","clover","four","four-leaf clover","leaf","vegetable","plant","nature","lucky","irish"]},"maple-leaf":{"a":"Maple Leaf","b":"1F341","j":["falling","leaf","maple","nature","plant","vegetable","ca","fall"]},"fallen-leaf":{"a":"Fallen Leaf","b":"1F342","j":["falling","leaf","nature","plant","vegetable","leaves"]},"leaf-fluttering-in-wind":{"a":"Leaf Fluttering in Wind","b":"1F343","j":["blow","flutter","leaf","wind","nature","plant","tree","vegetable","grass","lawn","spring"]},"empty-nest":{"a":"⊛ Empty Nest","b":"1FAB9","j":["nesting"]},"nest-with-eggs":{"a":"⊛ Nest with Eggs","b":"1FABA","j":["nesting"]},"grapes":{"a":"Grapes","b":"1F347","j":["fruit","grape","food","wine"]},"melon":{"a":"Melon","b":"1F348","j":["fruit","nature","food"]},"watermelon":{"a":"Watermelon","b":"1F349","j":["fruit","food","picnic","summer"]},"tangerine":{"a":"Tangerine","b":"1F34A","j":["fruit","orange","food","nature"]},"lemon":{"a":"Lemon","b":"1F34B","j":["citrus","fruit","nature"]},"banana":{"a":"Banana","b":"1F34C","j":["fruit","food","monkey"]},"pineapple":{"a":"Pineapple","b":"1F34D","j":["fruit","nature","food"]},"mango":{"a":"Mango","b":"1F96D","j":["fruit","tropical","food"]},"red-apple":{"a":"Red Apple","b":"1F34E","j":["apple","fruit","red","mac","school"]},"green-apple":{"a":"Green Apple","b":"1F34F","j":["apple","fruit","green","nature"]},"pear":{"a":"Pear","b":"1F350","j":["fruit","nature","food"]},"peach":{"a":"Peach","b":"1F351","j":["fruit","nature","food"]},"cherries":{"a":"Cherries","b":"1F352","j":["berries","cherry","fruit","red","food"]},"strawberry":{"a":"Strawberry","b":"1F353","j":["berry","fruit","food","nature"]},"blueberries":{"a":"Blueberries","b":"1FAD0","j":["berry","bilberry","blue","blueberry","fruit"]},"kiwi-fruit":{"a":"Kiwi Fruit","b":"1F95D","j":["food","fruit","kiwi"]},"tomato":{"a":"Tomato","b":"1F345","j":["fruit","vegetable","nature","food"]},"olive":{"a":"Olive","b":"1FAD2","j":["food","fruit"]},"coconut":{"a":"Coconut","b":"1F965","j":["palm","piña colada","fruit","nature","food"]},"avocado":{"a":"Avocado","b":"1F951","j":["food","fruit"]},"eggplant":{"a":"Eggplant","b":"1F346","j":["aubergine","vegetable","nature","food"]},"potato":{"a":"Potato","b":"1F954","j":["food","vegetable","tuber","vegatable","starch"]},"carrot":{"a":"Carrot","b":"1F955","j":["food","vegetable","orange"]},"ear-of-corn":{"a":"Ear of Corn","b":"1F33D","j":["corn","ear","maize","maze","food","vegetable","plant"]},"hot-pepper":{"a":"Hot Pepper","b":"1F336","j":["hot","pepper","food","spicy","chilli","chili"]},"bell-pepper":{"a":"Bell Pepper","b":"1FAD1","j":["capsicum","pepper","vegetable","fruit","plant"]},"cucumber":{"a":"Cucumber","b":"1F952","j":["food","pickle","vegetable","fruit"]},"leafy-green":{"a":"Leafy Green","b":"1F96C","j":["bok choy","cabbage","kale","lettuce","food","vegetable","plant"]},"broccoli":{"a":"Broccoli","b":"1F966","j":["wild cabbage","fruit","food","vegetable"]},"garlic":{"a":"Garlic","b":"1F9C4","j":["flavoring","food","spice","cook"]},"onion":{"a":"Onion","b":"1F9C5","j":["flavoring","cook","food","spice"]},"mushroom":{"a":"Mushroom","b":"1F344","j":["toadstool","plant","vegetable"]},"peanuts":{"a":"Peanuts","b":"1F95C","j":["food","nut","peanut","vegetable"]},"beans":{"a":"⊛ Beans","b":"1FAD8","j":["food","kidney","legume"]},"chestnut":{"a":"Chestnut","b":"1F330","j":["plant","food","squirrel"]},"bread":{"a":"Bread","b":"1F35E","j":["loaf","food","wheat","breakfast","toast"]},"croissant":{"a":"Croissant","b":"1F950","j":["bread","breakfast","food","french","roll"]},"baguette-bread":{"a":"Baguette Bread","b":"1F956","j":["baguette","bread","food","french"]},"flatbread":{"a":"Flatbread","b":"1FAD3","j":["arepa","lavash","naan","pita","flour","food"]},"pretzel":{"a":"Pretzel","b":"1F968","j":["twisted","convoluted","food","bread"]},"bagel":{"a":"Bagel","b":"1F96F","j":["bakery","breakfast","schmear","food","bread"]},"pancakes":{"a":"Pancakes","b":"1F95E","j":["breakfast","crêpe","food","hotcake","pancake","flapjacks","hotcakes"]},"waffle":{"a":"Waffle","b":"1F9C7","j":["breakfast","indecisive","iron","food"]},"cheese-wedge":{"a":"Cheese Wedge","b":"1F9C0","j":["cheese","food","chadder"]},"meat-on-bone":{"a":"Meat on Bone","b":"1F356","j":["bone","meat","good","food","drumstick"]},"poultry-leg":{"a":"Poultry Leg","b":"1F357","j":["bone","chicken","drumstick","leg","poultry","food","meat","bird","turkey"]},"cut-of-meat":{"a":"Cut of Meat","b":"1F969","j":["chop","lambchop","porkchop","steak","food","cow","meat","cut"]},"bacon":{"a":"Bacon","b":"1F953","j":["breakfast","food","meat","pork","pig"]},"hamburger":{"a":"Hamburger","b":"1F354","j":["burger","meat","fast food","beef","cheeseburger","mcdonalds","burger king"]},"french-fries":{"a":"French Fries","b":"1F35F","j":["french","fries","chips","snack","fast food"]},"pizza":{"a":"Pizza","b":"1F355","j":["cheese","slice","food","party"]},"hot-dog":{"a":"Hot Dog","b":"1F32D","j":["frankfurter","hotdog","sausage","food"]},"sandwich":{"a":"Sandwich","b":"1F96A","j":["bread","food","lunch"]},"taco":{"a":"Taco","b":"1F32E","j":["mexican","food"]},"burrito":{"a":"Burrito","b":"1F32F","j":["mexican","wrap","food"]},"tamale":{"a":"Tamale","b":"1FAD4","j":["mexican","wrapped","food","masa"]},"stuffed-flatbread":{"a":"Stuffed Flatbread","b":"1F959","j":["falafel","flatbread","food","gyro","kebab","stuffed"]},"falafel":{"a":"Falafel","b":"1F9C6","j":["chickpea","meatball","food"]},"egg":{"a":"Egg","b":"1F95A","j":["breakfast","food","chicken"]},"cooking":{"a":"Cooking","b":"1F373","j":["breakfast","egg","frying","pan","food","kitchen"]},"shallow-pan-of-food":{"a":"Shallow Pan of Food","b":"1F958","j":["casserole","food","paella","pan","shallow","cooking"]},"pot-of-food":{"a":"Pot of Food","b":"1F372","j":["pot","stew","food","meat","soup"]},"fondue":{"a":"Fondue","b":"1FAD5","j":["cheese","chocolate","melted","pot","Swiss","food"]},"bowl-with-spoon":{"a":"Bowl with Spoon","b":"1F963","j":["breakfast","cereal","congee","oatmeal","porridge","food"]},"green-salad":{"a":"Green Salad","b":"1F957","j":["food","green","salad","healthy","lettuce"]},"popcorn":{"a":"Popcorn","b":"1F37F","j":["food","movie theater","films","snack"]},"butter":{"a":"Butter","b":"1F9C8","j":["dairy","food","cook"]},"salt":{"a":"Salt","b":"1F9C2","j":["condiment","shaker"]},"canned-food":{"a":"Canned Food","b":"1F96B","j":["can","food","soup"]},"bento-box":{"a":"Bento Box","b":"1F371","j":["bento","box","food","japanese"]},"rice-cracker":{"a":"Rice Cracker","b":"1F358","j":["cracker","rice","food","japanese"]},"rice-ball":{"a":"Rice Ball","b":"1F359","j":["ball","Japanese","rice","food","japanese"]},"cooked-rice":{"a":"Cooked Rice","b":"1F35A","j":["cooked","rice","food","china","asian"]},"curry-rice":{"a":"Curry Rice","b":"1F35B","j":["curry","rice","food","spicy","hot","indian"]},"steaming-bowl":{"a":"Steaming Bowl","b":"1F35C","j":["bowl","noodle","ramen","steaming","food","japanese","chopsticks"]},"spaghetti":{"a":"Spaghetti","b":"1F35D","j":["pasta","food","italian","noodle"]},"roasted-sweet-potato":{"a":"Roasted Sweet Potato","b":"1F360","j":["potato","roasted","sweet","food","nature"]},"oden":{"a":"Oden","b":"1F362","j":["kebab","seafood","skewer","stick","food","japanese"]},"sushi":{"a":"Sushi","b":"1F363","j":["food","fish","japanese","rice"]},"fried-shrimp":{"a":"Fried Shrimp","b":"1F364","j":["fried","prawn","shrimp","tempura","food","animal","appetizer","summer"]},"fish-cake-with-swirl":{"a":"Fish Cake with Swirl","b":"1F365","j":["cake","fish","pastry","swirl","food","japan","sea","beach","narutomaki","pink","kamaboko","surimi","ramen"]},"moon-cake":{"a":"Moon Cake","b":"1F96E","j":["autumn","festival","yuèbǐng","food"]},"dango":{"a":"Dango","b":"1F361","j":["dessert","Japanese","skewer","stick","sweet","food","japanese","barbecue","meat"]},"dumpling":{"a":"Dumpling","b":"1F95F","j":["empanada","gyōza","jiaozi","pierogi","potsticker","food"]},"fortune-cookie":{"a":"Fortune Cookie","b":"1F960","j":["prophecy","food"]},"takeout-box":{"a":"Takeout Box","b":"1F961","j":["oyster pail","food","leftovers"]},"crab":{"a":"Crab","b":"1F980","j":["Cancer","zodiac","animal","crustacean"]},"lobster":{"a":"Lobster","b":"1F99E","j":["bisque","claws","seafood","animal","nature"]},"shrimp":{"a":"Shrimp","b":"1F990","j":["food","shellfish","small","animal","ocean","nature","seafood"]},"squid":{"a":"Squid","b":"1F991","j":["food","molusc","animal","nature","ocean","sea"]},"oyster":{"a":"Oyster","b":"1F9AA","j":["diving","pearl","food"]},"soft-ice-cream":{"a":"Soft Ice Cream","b":"1F366","j":["cream","dessert","ice","icecream","soft","sweet","food","hot","summer"]},"shaved-ice":{"a":"Shaved Ice","b":"1F367","j":["dessert","ice","shaved","sweet","hot","summer"]},"ice-cream":{"a":"Ice Cream","b":"1F368","j":["cream","dessert","ice","sweet","food","hot"]},"doughnut":{"a":"Doughnut","b":"1F369","j":["breakfast","dessert","donut","sweet","food","snack"]},"cookie":{"a":"Cookie","b":"1F36A","j":["dessert","sweet","food","snack","oreo","chocolate"]},"birthday-cake":{"a":"Birthday Cake","b":"1F382","j":["birthday","cake","celebration","dessert","pastry","sweet","food"]},"shortcake":{"a":"Shortcake","b":"1F370","j":["cake","dessert","pastry","slice","sweet","food"]},"cupcake":{"a":"Cupcake","b":"1F9C1","j":["bakery","sweet","food","dessert"]},"pie":{"a":"Pie","b":"1F967","j":["filling","pastry","fruit","meat","food","dessert"]},"chocolate-bar":{"a":"Chocolate Bar","b":"1F36B","j":["bar","chocolate","dessert","sweet","food","snack"]},"candy":{"a":"Candy","b":"1F36C","j":["dessert","sweet","snack","lolly"]},"lollipop":{"a":"Lollipop","b":"1F36D","j":["candy","dessert","sweet","food","snack"]},"custard":{"a":"Custard","b":"1F36E","j":["dessert","pudding","sweet","food"]},"honey-pot":{"a":"Honey Pot","b":"1F36F","j":["honey","honeypot","pot","sweet","bees","kitchen"]},"baby-bottle":{"a":"Baby Bottle","b":"1F37C","j":["baby","bottle","drink","milk","food","container"]},"glass-of-milk":{"a":"Glass of Milk","b":"1F95B","j":["drink","glass","milk","beverage","cow"]},"hot-beverage":{"a":"Hot Beverage","b":"2615","j":["beverage","coffee","drink","hot","steaming","tea","caffeine","latte","espresso"]},"teapot":{"a":"Teapot","b":"1FAD6","j":["drink","pot","tea","hot"]},"teacup-without-handle":{"a":"Teacup Without Handle","b":"1F375","j":["beverage","cup","drink","tea","teacup","bowl","breakfast","green","british"]},"sake":{"a":"Sake","b":"1F376","j":["bar","beverage","bottle","cup","drink","wine","drunk","japanese","alcohol","booze"]},"bottle-with-popping-cork":{"a":"Bottle with Popping Cork","b":"1F37E","j":["bar","bottle","cork","drink","popping","wine","celebration"]},"wine-glass":{"a":"Wine Glass","b":"1F377","j":["bar","beverage","drink","glass","wine","drunk","alcohol","booze"]},"cocktail-glass":{"a":"Cocktail Glass","b":"1F378","j":["bar","cocktail","drink","glass","drunk","alcohol","beverage","booze","mojito"]},"tropical-drink":{"a":"Tropical Drink","b":"1F379","j":["bar","drink","tropical","beverage","cocktail","summer","beach","alcohol","booze","mojito"]},"beer-mug":{"a":"Beer Mug","b":"1F37A","j":["bar","beer","drink","mug","relax","beverage","drunk","party","pub","summer","alcohol","booze"]},"clinking-beer-mugs":{"a":"Clinking Beer Mugs","b":"1F37B","j":["bar","beer","clink","drink","mug","relax","beverage","drunk","party","pub","summer","alcohol","booze"]},"clinking-glasses":{"a":"Clinking Glasses","b":"1F942","j":["celebrate","clink","drink","glass","beverage","party","alcohol","cheers","wine","champagne","toast"]},"tumbler-glass":{"a":"Tumbler Glass","b":"1F943","j":["glass","liquor","shot","tumbler","whisky","drink","beverage","drunk","alcohol","booze","bourbon","scotch"]},"pouring-liquid":{"a":"⊛ Pouring Liquid","b":"1FAD7","j":["drink","empty","glass","spill"]},"cup-with-straw":{"a":"Cup with Straw","b":"1F964","j":["juice","soda","malt","soft drink","water","drink"]},"bubble-tea":{"a":"Bubble Tea","b":"1F9CB","j":["bubble","milk","pearl","tea","taiwan","boba","milk tea","straw"]},"beverage-box":{"a":"Beverage Box","b":"1F9C3","j":["beverage","box","juice","straw","sweet","drink"]},"mate":{"a":"Mate","b":"1F9C9","j":["drink","tea","beverage"]},"ice":{"a":"Ice","b":"1F9CA","j":["cold","ice cube","iceberg","water"]},"chopsticks":{"a":"Chopsticks","b":"1F962","j":["hashi","jeotgarak","kuaizi","food"]},"fork-and-knife-with-plate":{"a":"Fork and Knife with Plate","b":"1F37D","j":["cooking","fork","knife","plate","food","eat","meal","lunch","dinner","restaurant"]},"fork-and-knife":{"a":"Fork and Knife","b":"1F374","j":["cooking","cutlery","fork","knife","kitchen"]},"spoon":{"a":"Spoon","b":"1F944","j":["tableware","cutlery","kitchen"]},"kitchen-knife":{"a":"Kitchen Knife","b":"1F52A","j":["cooking","hocho","knife","tool","weapon","blade","cutlery","kitchen"]},"jar":{"a":"⊛ Jar","b":"1FAD9","j":["condiment","container","empty","sauce","store"]},"amphora":{"a":"Amphora","b":"1F3FA","j":["Aquarius","cooking","drink","jug","zodiac","vase","jar"]},"globe-showing-europeafrica":{"a":"Globe Showing Europe-Africa","b":"1F30D","j":["Africa","earth","Europe","globe","globe showing Europe-Africa","world","globe_showing_europe_africa","international"]},"globe-showing-americas":{"a":"Globe Showing Americas","b":"1F30E","j":["Americas","earth","globe","globe showing Americas","world","USA","international"]},"globe-showing-asiaaustralia":{"a":"Globe Showing Asia-Australia","b":"1F30F","j":["Asia","Australia","earth","globe","globe showing Asia-Australia","world","globe_showing_asia_australia","east","international"]},"globe-with-meridians":{"a":"Globe with Meridians","b":"1F310","j":["earth","globe","meridians","world","international","internet","interweb","i18n"]},"world-map":{"a":"World Map","b":"1F5FA","j":["map","world","location","direction"]},"map-of-japan":{"a":"Map of Japan","b":"1F5FE","j":["Japan","map","map of Japan","nation","country","japanese","asia"]},"compass":{"a":"Compass","b":"1F9ED","j":["magnetic","navigation","orienteering"]},"snowcapped-mountain":{"a":"Snow-Capped Mountain","b":"1F3D4","j":["cold","mountain","snow","snow-capped mountain","snow_capped_mountain","photo","nature","environment","winter"]},"mountain":{"a":"Mountain","b":"26F0","j":["photo","nature","environment"]},"volcano":{"a":"Volcano","b":"1F30B","j":["eruption","mountain","photo","nature","disaster"]},"mount-fuji":{"a":"Mount Fuji","b":"1F5FB","j":["fuji","mountain","photo","nature","japanese"]},"camping":{"a":"Camping","b":"1F3D5","j":["photo","outdoors","tent"]},"beach-with-umbrella":{"a":"Beach with Umbrella","b":"1F3D6","j":["beach","umbrella","weather","summer","sunny","sand","mojito"]},"desert":{"a":"Desert","b":"1F3DC","j":["photo","warm","saharah"]},"desert-island":{"a":"Desert Island","b":"1F3DD","j":["desert","island","photo","tropical","mojito"]},"national-park":{"a":"National Park","b":"1F3DE","j":["park","photo","environment","nature"]},"stadium":{"a":"Stadium","b":"1F3DF","j":["photo","place","sports","concert","venue"]},"classical-building":{"a":"Classical Building","b":"1F3DB","j":["classical","art","culture","history"]},"building-construction":{"a":"Building Construction","b":"1F3D7","j":["construction","wip","working","progress"]},"brick":{"a":"Brick","b":"1F9F1","j":["bricks","clay","mortar","wall"]},"rock":{"a":"Rock","b":"1FAA8","j":["boulder","heavy","solid","stone"]},"wood":{"a":"Wood","b":"1FAB5","j":["log","lumber","timber","nature","trunk"]},"hut":{"a":"Hut","b":"1F6D6","j":["house","roundhouse","yurt","structure"]},"houses":{"a":"Houses","b":"1F3D8","j":["buildings","photo"]},"derelict-house":{"a":"Derelict House","b":"1F3DA","j":["derelict","house","abandon","evict","broken","building"]},"house":{"a":"House","b":"1F3E0","j":["home","building"]},"house-with-garden":{"a":"House with Garden","b":"1F3E1","j":["garden","home","house","plant","nature"]},"office-building":{"a":"Office Building","b":"1F3E2","j":["building","bureau","work"]},"japanese-post-office":{"a":"Japanese Post Office","b":"1F3E3","j":["Japanese","Japanese post office","post","building","envelope","communication"]},"post-office":{"a":"Post Office","b":"1F3E4","j":["European","post","building","email"]},"hospital":{"a":"Hospital","b":"1F3E5","j":["doctor","medicine","building","health","surgery"]},"bank":{"a":"Bank","b":"1F3E6","j":["building","money","sales","cash","business","enterprise"]},"hotel":{"a":"Hotel","b":"1F3E8","j":["building","accomodation","checkin"]},"love-hotel":{"a":"Love Hotel","b":"1F3E9","j":["hotel","love","like","affection","dating"]},"convenience-store":{"a":"Convenience Store","b":"1F3EA","j":["convenience","store","building","shopping","groceries"]},"school":{"a":"School","b":"1F3EB","j":["building","student","education","learn","teach"]},"department-store":{"a":"Department Store","b":"1F3EC","j":["department","store","building","shopping","mall"]},"factory":{"a":"Factory","b":"1F3ED","j":["building","industry","pollution","smoke"]},"japanese-castle":{"a":"Japanese Castle","b":"1F3EF","j":["castle","Japanese","photo","building"]},"castle":{"a":"Castle","b":"1F3F0","j":["European","building","royalty","history"]},"wedding":{"a":"Wedding","b":"1F492","j":["chapel","romance","love","like","affection","couple","marriage","bride","groom"]},"tokyo-tower":{"a":"Tokyo Tower","b":"1F5FC","j":["Tokyo","tower","photo","japanese"]},"statue-of-liberty":{"a":"Statue of Liberty","b":"1F5FD","j":["liberty","statue","american","newyork"]},"church":{"a":"Church","b":"26EA","j":["Christian","cross","religion","building","christ"]},"mosque":{"a":"Mosque","b":"1F54C","j":["islam","Muslim","religion","worship","minaret"]},"hindu-temple":{"a":"Hindu Temple","b":"1F6D5","j":["hindu","temple","religion"]},"synagogue":{"a":"Synagogue","b":"1F54D","j":["Jew","Jewish","religion","temple","judaism","worship","jewish"]},"shinto-shrine":{"a":"Shinto Shrine","b":"26E9","j":["religion","shinto","shrine","temple","japan","kyoto"]},"kaaba":{"a":"Kaaba","b":"1F54B","j":["islam","Muslim","religion","mecca","mosque"]},"fountain":{"a":"Fountain","b":"26F2","j":["photo","summer","water","fresh"]},"tent":{"a":"Tent","b":"26FA","j":["camping","photo","outdoors"]},"foggy":{"a":"Foggy","b":"1F301","j":["fog","photo","mountain"]},"night-with-stars":{"a":"Night with Stars","b":"1F303","j":["night","star","evening","city","downtown"]},"cityscape":{"a":"Cityscape","b":"1F3D9","j":["city","photo","night life","urban"]},"sunrise-over-mountains":{"a":"Sunrise over Mountains","b":"1F304","j":["morning","mountain","sun","sunrise","view","vacation","photo"]},"sunrise":{"a":"Sunrise","b":"1F305","j":["morning","sun","view","vacation","photo"]},"cityscape-at-dusk":{"a":"Cityscape at Dusk","b":"1F306","j":["city","dusk","evening","landscape","sunset","photo","sky","buildings"]},"sunset":{"a":"Sunset","b":"1F307","j":["dusk","sun","photo","good morning","dawn"]},"bridge-at-night":{"a":"Bridge at Night","b":"1F309","j":["bridge","night","photo","sanfrancisco"]},"hot-springs":{"a":"Hot Springs","b":"2668","j":["hot","hotsprings","springs","steaming","bath","warm","relax"]},"carousel-horse":{"a":"Carousel Horse","b":"1F3A0","j":["carousel","horse","photo","carnival"]},"playground-slide":{"a":"⊛ Playground Slide","b":"1F6DD","j":["amusement park","play"]},"ferris-wheel":{"a":"Ferris Wheel","b":"1F3A1","j":["amusement park","ferris","wheel","photo","carnival","londoneye"]},"roller-coaster":{"a":"Roller Coaster","b":"1F3A2","j":["amusement park","coaster","roller","carnival","playground","photo","fun"]},"barber-pole":{"a":"Barber Pole","b":"1F488","j":["barber","haircut","pole","hair","salon","style"]},"circus-tent":{"a":"Circus Tent","b":"1F3AA","j":["circus","tent","festival","carnival","party"]},"locomotive":{"a":"Locomotive","b":"1F682","j":["engine","railway","steam","train","transportation","vehicle"]},"railway-car":{"a":"Railway Car","b":"1F683","j":["car","electric","railway","train","tram","trolleybus","transportation","vehicle"]},"highspeed-train":{"a":"High-Speed Train","b":"1F684","j":["high-speed train","railway","shinkansen","speed","train","high_speed_train","transportation","vehicle"]},"bullet-train":{"a":"Bullet Train","b":"1F685","j":["bullet","railway","shinkansen","speed","train","transportation","vehicle","fast","public","travel"]},"train":{"a":"Train","b":"1F686","j":["railway","transportation","vehicle"]},"metro":{"a":"Metro","b":"1F687","j":["subway","transportation","blue-square","mrt","underground","tube"]},"light-rail":{"a":"Light Rail","b":"1F688","j":["railway","transportation","vehicle"]},"station":{"a":"Station","b":"1F689","j":["railway","train","transportation","vehicle","public"]},"tram":{"a":"Tram","b":"1F68A","j":["trolleybus","transportation","vehicle"]},"monorail":{"a":"Monorail","b":"1F69D","j":["vehicle","transportation"]},"mountain-railway":{"a":"Mountain Railway","b":"1F69E","j":["car","mountain","railway","transportation","vehicle"]},"tram-car":{"a":"Tram Car","b":"1F68B","j":["car","tram","trolleybus","transportation","vehicle","carriage","public","travel"]},"bus":{"a":"Bus","b":"1F68C","j":["vehicle","car","transportation"]},"oncoming-bus":{"a":"Oncoming Bus","b":"1F68D","j":["bus","oncoming","vehicle","transportation"]},"trolleybus":{"a":"Trolleybus","b":"1F68E","j":["bus","tram","trolley","bart","transportation","vehicle"]},"minibus":{"a":"Minibus","b":"1F690","j":["bus","vehicle","car","transportation"]},"ambulance":{"a":"Ambulance","b":"1F691","j":["vehicle","health","911","hospital"]},"fire-engine":{"a":"Fire Engine","b":"1F692","j":["engine","fire","truck","transportation","cars","vehicle"]},"police-car":{"a":"Police Car","b":"1F693","j":["car","patrol","police","vehicle","cars","transportation","law","legal","enforcement"]},"oncoming-police-car":{"a":"Oncoming Police Car","b":"1F694","j":["car","oncoming","police","vehicle","law","legal","enforcement","911"]},"taxi":{"a":"Taxi","b":"1F695","j":["vehicle","uber","cars","transportation"]},"oncoming-taxi":{"a":"Oncoming Taxi","b":"1F696","j":["oncoming","taxi","vehicle","cars","uber"]},"automobile":{"a":"Automobile","b":"1F697","j":["car","red","transportation","vehicle"]},"oncoming-automobile":{"a":"Oncoming Automobile","b":"1F698","j":["automobile","car","oncoming","vehicle","transportation"]},"sport-utility-vehicle":{"a":"Sport Utility Vehicle","b":"1F699","j":["recreational","sport utility","transportation","vehicle"]},"pickup-truck":{"a":"Pickup Truck","b":"1F6FB","j":["pick-up","pickup","truck","car","transportation"]},"delivery-truck":{"a":"Delivery Truck","b":"1F69A","j":["delivery","truck","cars","transportation"]},"articulated-lorry":{"a":"Articulated Lorry","b":"1F69B","j":["lorry","semi","truck","vehicle","cars","transportation","express"]},"tractor":{"a":"Tractor","b":"1F69C","j":["vehicle","car","farming","agriculture"]},"racing-car":{"a":"Racing Car","b":"1F3CE","j":["car","racing","sports","race","fast","formula","f1"]},"motorcycle":{"a":"Motorcycle","b":"1F3CD","j":["racing","race","sports","fast"]},"motor-scooter":{"a":"Motor Scooter","b":"1F6F5","j":["motor","scooter","vehicle","vespa","sasha"]},"manual-wheelchair":{"a":"Manual Wheelchair","b":"1F9BD","j":["accessibility"]},"motorized-wheelchair":{"a":"Motorized Wheelchair","b":"1F9BC","j":["accessibility"]},"auto-rickshaw":{"a":"Auto Rickshaw","b":"1F6FA","j":["tuk tuk","move","transportation"]},"bicycle":{"a":"Bicycle","b":"1F6B2","j":["bike","sports","exercise","hipster"]},"kick-scooter":{"a":"Kick Scooter","b":"1F6F4","j":["kick","scooter","vehicle","razor"]},"skateboard":{"a":"Skateboard","b":"1F6F9","j":["board"]},"roller-skate":{"a":"Roller Skate","b":"1F6FC","j":["roller","skate","footwear","sports"]},"bus-stop":{"a":"Bus Stop","b":"1F68F","j":["bus","stop","transportation","wait"]},"motorway":{"a":"Motorway","b":"1F6E3","j":["highway","road","cupertino","interstate"]},"railway-track":{"a":"Railway Track","b":"1F6E4","j":["railway","train","transportation"]},"oil-drum":{"a":"Oil Drum","b":"1F6E2","j":["drum","oil","barrell"]},"fuel-pump":{"a":"Fuel Pump","b":"26FD","j":["diesel","fuel","fuelpump","gas","pump","station","gas station","petroleum"]},"wheel":{"a":"⊛ Wheel","b":"1F6DE","j":["circle","tire","turn"]},"police-car-light":{"a":"Police Car Light","b":"1F6A8","j":["beacon","car","light","police","revolving","ambulance","911","emergency","alert","error","pinged","law","legal"]},"horizontal-traffic-light":{"a":"Horizontal Traffic Light","b":"1F6A5","j":["light","signal","traffic","transportation"]},"vertical-traffic-light":{"a":"Vertical Traffic Light","b":"1F6A6","j":["light","signal","traffic","transportation","driving"]},"stop-sign":{"a":"Stop Sign","b":"1F6D1","j":["octagonal","sign","stop"]},"construction":{"a":"Construction","b":"1F6A7","j":["barrier","wip","progress","caution","warning"]},"anchor":{"a":"Anchor","b":"2693","j":["ship","tool","ferry","sea","boat"]},"ring-buoy":{"a":"⊛ Ring Buoy","b":"1F6DF","j":["float","life preserver","life saver","rescue","safety"]},"sailboat":{"a":"Sailboat","b":"26F5","j":["boat","resort","sea","yacht","ship","summer","transportation","water","sailing"]},"canoe":{"a":"Canoe","b":"1F6F6","j":["boat","paddle","water","ship"]},"speedboat":{"a":"Speedboat","b":"1F6A4","j":["boat","ship","transportation","vehicle","summer"]},"passenger-ship":{"a":"Passenger Ship","b":"1F6F3","j":["passenger","ship","yacht","cruise","ferry"]},"ferry":{"a":"Ferry","b":"26F4","j":["boat","passenger","ship","yacht"]},"motor-boat":{"a":"Motor Boat","b":"1F6E5","j":["boat","motorboat","ship"]},"ship":{"a":"Ship","b":"1F6A2","j":["boat","passenger","transportation","titanic","deploy"]},"airplane":{"a":"Airplane","b":"2708","j":["aeroplane","vehicle","transportation","flight","fly"]},"small-airplane":{"a":"Small Airplane","b":"1F6E9","j":["aeroplane","airplane","flight","transportation","fly","vehicle"]},"airplane-departure":{"a":"Airplane Departure","b":"1F6EB","j":["aeroplane","airplane","check-in","departure","departures","airport","flight","landing"]},"airplane-arrival":{"a":"Airplane Arrival","b":"1F6EC","j":["aeroplane","airplane","arrivals","arriving","landing","airport","flight","boarding"]},"parachute":{"a":"Parachute","b":"1FA82","j":["hang-glide","parasail","skydive","fly","glide"]},"seat":{"a":"Seat","b":"1F4BA","j":["chair","sit","airplane","transport","bus","flight","fly"]},"helicopter":{"a":"Helicopter","b":"1F681","j":["vehicle","transportation","fly"]},"suspension-railway":{"a":"Suspension Railway","b":"1F69F","j":["railway","suspension","vehicle","transportation"]},"mountain-cableway":{"a":"Mountain Cableway","b":"1F6A0","j":["cable","gondola","mountain","transportation","vehicle","ski"]},"aerial-tramway":{"a":"Aerial Tramway","b":"1F6A1","j":["aerial","cable","car","gondola","tramway","transportation","vehicle","ski"]},"satellite":{"a":"Satellite","b":"1F6F0","j":["space","communication","gps","orbit","spaceflight","NASA","ISS"]},"rocket":{"a":"Rocket","b":"1F680","j":["space","launch","ship","staffmode","NASA","outer space","outer_space","fly"]},"flying-saucer":{"a":"Flying Saucer","b":"1F6F8","j":["UFO","transportation","vehicle","ufo"]},"bellhop-bell":{"a":"Bellhop Bell","b":"1F6CE","j":["bell","bellhop","hotel","service"]},"luggage":{"a":"Luggage","b":"1F9F3","j":["packing","travel"]},"hourglass-done":{"a":"Hourglass Done","b":"231B","j":["sand","timer","time","clock","oldschool","limit","exam","quiz","test"]},"hourglass-not-done":{"a":"Hourglass Not Done","b":"23F3","j":["hourglass","sand","timer","oldschool","time","countdown"]},"watch":{"a":"Watch","b":"231A","j":["clock","time","accessories"]},"alarm-clock":{"a":"Alarm Clock","b":"23F0","j":["alarm","clock","time","wake"]},"stopwatch":{"a":"Stopwatch","b":"23F1","j":["clock","time","deadline"]},"timer-clock":{"a":"Timer Clock","b":"23F2","j":["clock","timer","alarm"]},"mantelpiece-clock":{"a":"Mantelpiece Clock","b":"1F570","j":["clock","time"]},"twelve-oclock":{"a":"Twelve O’Clock","b":"1F55B","j":["00","12","12:00","clock","o’clock","twelve","twelve_o_clock","time","noon","midnight","midday","late","early","schedule"]},"twelvethirty":{"a":"Twelve-Thirty","b":"1F567","j":["12","12:30","clock","thirty","twelve","twelve-thirty","twelve_thirty","time","late","early","schedule"]},"one-oclock":{"a":"One O’Clock","b":"1F550","j":["00","1","1:00","clock","o’clock","one","one_o_clock","time","late","early","schedule"]},"onethirty":{"a":"One-Thirty","b":"1F55C","j":["1","1:30","clock","one","one-thirty","thirty","one_thirty","time","late","early","schedule"]},"two-oclock":{"a":"Two O’Clock","b":"1F551","j":["00","2","2:00","clock","o’clock","two","two_o_clock","time","late","early","schedule"]},"twothirty":{"a":"Two-Thirty","b":"1F55D","j":["2","2:30","clock","thirty","two","two-thirty","two_thirty","time","late","early","schedule"]},"three-oclock":{"a":"Three O’Clock","b":"1F552","j":["00","3","3:00","clock","o’clock","three","three_o_clock","time","late","early","schedule"]},"threethirty":{"a":"Three-Thirty","b":"1F55E","j":["3","3:30","clock","thirty","three","three-thirty","three_thirty","time","late","early","schedule"]},"four-oclock":{"a":"Four O’Clock","b":"1F553","j":["00","4","4:00","clock","four","o’clock","four_o_clock","time","late","early","schedule"]},"fourthirty":{"a":"Four-Thirty","b":"1F55F","j":["4","4:30","clock","four","four-thirty","thirty","four_thirty","time","late","early","schedule"]},"five-oclock":{"a":"Five O’Clock","b":"1F554","j":["00","5","5:00","clock","five","o’clock","five_o_clock","time","late","early","schedule"]},"fivethirty":{"a":"Five-Thirty","b":"1F560","j":["5","5:30","clock","five","five-thirty","thirty","five_thirty","time","late","early","schedule"]},"six-oclock":{"a":"Six O’Clock","b":"1F555","j":["00","6","6:00","clock","o’clock","six","six_o_clock","time","late","early","schedule","dawn","dusk"]},"sixthirty":{"a":"Six-Thirty","b":"1F561","j":["6","6:30","clock","six","six-thirty","thirty","six_thirty","time","late","early","schedule"]},"seven-oclock":{"a":"Seven O’Clock","b":"1F556","j":["00","7","7:00","clock","o’clock","seven","seven_o_clock","time","late","early","schedule"]},"seventhirty":{"a":"Seven-Thirty","b":"1F562","j":["7","7:30","clock","seven","seven-thirty","thirty","seven_thirty","time","late","early","schedule"]},"eight-oclock":{"a":"Eight O’Clock","b":"1F557","j":["00","8","8:00","clock","eight","o’clock","eight_o_clock","time","late","early","schedule"]},"eightthirty":{"a":"Eight-Thirty","b":"1F563","j":["8","8:30","clock","eight","eight-thirty","thirty","eight_thirty","time","late","early","schedule"]},"nine-oclock":{"a":"Nine O’Clock","b":"1F558","j":["00","9","9:00","clock","nine","o’clock","nine_o_clock","time","late","early","schedule"]},"ninethirty":{"a":"Nine-Thirty","b":"1F564","j":["9","9:30","clock","nine","nine-thirty","thirty","nine_thirty","time","late","early","schedule"]},"ten-oclock":{"a":"Ten O’Clock","b":"1F559","j":["00","10","10:00","clock","o’clock","ten","ten_o_clock","time","late","early","schedule"]},"tenthirty":{"a":"Ten-Thirty","b":"1F565","j":["10","10:30","clock","ten","ten-thirty","thirty","ten_thirty","time","late","early","schedule"]},"eleven-oclock":{"a":"Eleven O’Clock","b":"1F55A","j":["00","11","11:00","clock","eleven","o’clock","eleven_o_clock","time","late","early","schedule"]},"eleventhirty":{"a":"Eleven-Thirty","b":"1F566","j":["11","11:30","clock","eleven","eleven-thirty","thirty","eleven_thirty","time","late","early","schedule"]},"new-moon":{"a":"New Moon","b":"1F311","j":["dark","moon","nature","twilight","planet","space","night","evening","sleep"]},"waxing-crescent-moon":{"a":"Waxing Crescent Moon","b":"1F312","j":["crescent","moon","waxing","nature","twilight","planet","space","night","evening","sleep"]},"first-quarter-moon":{"a":"First Quarter Moon","b":"1F313","j":["moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"waxing-gibbous-moon":{"a":"Waxing Gibbous Moon","b":"1F314","j":["gibbous","moon","waxing","nature","night","sky","gray","twilight","planet","space","evening","sleep"]},"full-moon":{"a":"Full Moon","b":"1F315","j":["full","moon","nature","yellow","twilight","planet","space","night","evening","sleep"]},"waning-gibbous-moon":{"a":"Waning Gibbous Moon","b":"1F316","j":["gibbous","moon","waning","nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"]},"last-quarter-moon":{"a":"Last Quarter Moon","b":"1F317","j":["moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"waning-crescent-moon":{"a":"Waning Crescent Moon","b":"1F318","j":["crescent","moon","waning","nature","twilight","planet","space","night","evening","sleep"]},"crescent-moon":{"a":"Crescent Moon","b":"1F319","j":["crescent","moon","night","sleep","sky","evening","magic"]},"new-moon-face":{"a":"New Moon Face","b":"1F31A","j":["face","moon","nature","twilight","planet","space","night","evening","sleep"]},"first-quarter-moon-face":{"a":"First Quarter Moon Face","b":"1F31B","j":["face","moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"last-quarter-moon-face":{"a":"Last Quarter Moon Face","b":"1F31C","j":["face","moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"thermometer":{"a":"Thermometer","b":"1F321","j":["weather","temperature","hot","cold"]},"sun":{"a":"Sun","b":"2600","j":["bright","rays","sunny","weather","nature","brightness","summer","beach","spring"]},"full-moon-face":{"a":"Full Moon Face","b":"1F31D","j":["bright","face","full","moon","nature","twilight","planet","space","night","evening","sleep"]},"sun-with-face":{"a":"Sun with Face","b":"1F31E","j":["bright","face","sun","nature","morning","sky"]},"ringed-planet":{"a":"Ringed Planet","b":"1FA90","j":["saturn","saturnine","outerspace"]},"star":{"a":"Star","b":"2B50","j":["night","yellow"]},"glowing-star":{"a":"Glowing Star","b":"1F31F","j":["glittery","glow","shining","sparkle","star","night","awesome","good","magic"]},"shooting-star":{"a":"Shooting Star","b":"1F320","j":["falling","shooting","star","night","photo"]},"milky-way":{"a":"Milky Way","b":"1F30C","j":["space","photo","stars"]},"cloud":{"a":"Cloud","b":"2601","j":["weather","sky"]},"sun-behind-cloud":{"a":"Sun Behind Cloud","b":"26C5","j":["cloud","sun","weather","nature","cloudy","morning","fall","spring"]},"cloud-with-lightning-and-rain":{"a":"Cloud with Lightning and Rain","b":"26C8","j":["cloud","rain","thunder","weather","lightning"]},"sun-behind-small-cloud":{"a":"Sun Behind Small Cloud","b":"1F324","j":["cloud","sun","weather"]},"sun-behind-large-cloud":{"a":"Sun Behind Large Cloud","b":"1F325","j":["cloud","sun","weather"]},"sun-behind-rain-cloud":{"a":"Sun Behind Rain Cloud","b":"1F326","j":["cloud","rain","sun","weather"]},"cloud-with-rain":{"a":"Cloud with Rain","b":"1F327","j":["cloud","rain","weather"]},"cloud-with-snow":{"a":"Cloud with Snow","b":"1F328","j":["cloud","cold","snow","weather"]},"cloud-with-lightning":{"a":"Cloud with Lightning","b":"1F329","j":["cloud","lightning","weather","thunder"]},"tornado":{"a":"Tornado","b":"1F32A","j":["cloud","whirlwind","weather","cyclone","twister"]},"fog":{"a":"Fog","b":"1F32B","j":["cloud","weather"]},"wind-face":{"a":"Wind Face","b":"1F32C","j":["blow","cloud","face","wind","gust","air"]},"cyclone":{"a":"Cyclone","b":"1F300","j":["dizzy","hurricane","twister","typhoon","weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado"]},"rainbow":{"a":"Rainbow","b":"1F308","j":["rain","nature","happy","unicorn_face","photo","sky","spring"]},"closed-umbrella":{"a":"Closed Umbrella","b":"1F302","j":["clothing","rain","umbrella","weather","drizzle"]},"umbrella":{"a":"Umbrella","b":"2602","j":["clothing","rain","weather","spring"]},"umbrella-with-rain-drops":{"a":"Umbrella with Rain Drops","b":"2614","j":["clothing","drop","rain","umbrella","rainy","weather","spring"]},"umbrella-on-ground":{"a":"Umbrella on Ground","b":"26F1","j":["rain","sun","umbrella","weather","summer"]},"high-voltage":{"a":"High Voltage","b":"26A1","j":["danger","electric","lightning","voltage","zap","thunder","weather","lightning bolt","fast"]},"snowflake":{"a":"Snowflake","b":"2744","j":["cold","snow","winter","season","weather","christmas","xmas"]},"snowman":{"a":"Snowman","b":"2603","j":["cold","snow","winter","season","weather","christmas","xmas","frozen"]},"snowman-without-snow":{"a":"Snowman Without Snow","b":"26C4","j":["cold","snow","snowman","winter","season","weather","christmas","xmas","frozen","without_snow"]},"comet":{"a":"Comet","b":"2604","j":["space"]},"fire":{"a":"Fire","b":"1F525","j":["flame","tool","hot","cook"]},"droplet":{"a":"Droplet","b":"1F4A7","j":["cold","comic","drop","sweat","water","drip","faucet","spring"]},"water-wave":{"a":"Water Wave","b":"1F30A","j":["ocean","water","wave","sea","nature","tsunami","disaster"]},"jackolantern":{"a":"Jack-O-Lantern","b":"1F383","j":["celebration","halloween","jack","jack-o-lantern","lantern","jack_o_lantern","light","pumpkin","creepy","fall"]},"christmas-tree":{"a":"Christmas Tree","b":"1F384","j":["celebration","Christmas","tree","festival","vacation","december","xmas"]},"fireworks":{"a":"Fireworks","b":"1F386","j":["celebration","photo","festival","carnival","congratulations"]},"sparkler":{"a":"Sparkler","b":"1F387","j":["celebration","fireworks","sparkle","stars","night","shine"]},"firecracker":{"a":"Firecracker","b":"1F9E8","j":["dynamite","explosive","fireworks","boom","explode","explosion"]},"sparkles":{"a":"Sparkles","b":"2728","j":["*","sparkle","star","stars","shine","shiny","cool","awesome","good","magic"]},"balloon":{"a":"Balloon","b":"1F388","j":["celebration","party","birthday","circus"]},"party-popper":{"a":"Party Popper","b":"1F389","j":["celebration","party","popper","tada","congratulations","birthday","magic","circus"]},"confetti-ball":{"a":"Confetti Ball","b":"1F38A","j":["ball","celebration","confetti","festival","party","birthday","circus"]},"tanabata-tree":{"a":"Tanabata Tree","b":"1F38B","j":["banner","celebration","Japanese","tree","plant","nature","branch","summer"]},"pine-decoration":{"a":"Pine Decoration","b":"1F38D","j":["bamboo","celebration","Japanese","pine","plant","nature","vegetable","panda"]},"japanese-dolls":{"a":"Japanese Dolls","b":"1F38E","j":["celebration","doll","festival","Japanese","Japanese dolls","japanese","toy","kimono"]},"carp-streamer":{"a":"Carp Streamer","b":"1F38F","j":["carp","celebration","streamer","fish","japanese","koinobori","banner"]},"wind-chime":{"a":"Wind Chime","b":"1F390","j":["bell","celebration","chime","wind","nature","ding","spring"]},"moon-viewing-ceremony":{"a":"Moon Viewing Ceremony","b":"1F391","j":["celebration","ceremony","moon","photo","japan","asia","tsukimi"]},"red-envelope":{"a":"Red Envelope","b":"1F9E7","j":["gift","good luck","hóngbāo","lai see","money"]},"ribbon":{"a":"Ribbon","b":"1F380","j":["celebration","decoration","pink","girl","bowtie"]},"wrapped-gift":{"a":"Wrapped Gift","b":"1F381","j":["box","celebration","gift","present","wrapped","birthday","christmas","xmas"]},"reminder-ribbon":{"a":"Reminder Ribbon","b":"1F397","j":["celebration","reminder","ribbon","sports","cause","support","awareness"]},"admission-tickets":{"a":"Admission Tickets","b":"1F39F","j":["admission","ticket","sports","concert","entrance"]},"ticket":{"a":"Ticket","b":"1F3AB","j":["admission","event","concert","pass"]},"military-medal":{"a":"Military Medal","b":"1F396","j":["celebration","medal","military","award","winning","army"]},"trophy":{"a":"Trophy","b":"1F3C6","j":["prize","win","award","contest","place","ftw","ceremony"]},"sports-medal":{"a":"Sports Medal","b":"1F3C5","j":["medal","award","winning"]},"1st-place-medal":{"a":"1st Place Medal","b":"1F947","j":["first","gold","medal","award","winning"]},"2nd-place-medal":{"a":"2nd Place Medal","b":"1F948","j":["medal","second","silver","award"]},"3rd-place-medal":{"a":"3rd Place Medal","b":"1F949","j":["bronze","medal","third","award"]},"soccer-ball":{"a":"Soccer Ball","b":"26BD","j":["ball","football","soccer","sports"]},"baseball":{"a":"Baseball","b":"26BE","j":["ball","sports","balls"]},"softball":{"a":"Softball","b":"1F94E","j":["ball","glove","underarm","sports","balls"]},"basketball":{"a":"Basketball","b":"1F3C0","j":["ball","hoop","sports","balls","NBA"]},"volleyball":{"a":"Volleyball","b":"1F3D0","j":["ball","game","sports","balls"]},"american-football":{"a":"American Football","b":"1F3C8","j":["american","ball","football","sports","balls","NFL"]},"rugby-football":{"a":"Rugby Football","b":"1F3C9","j":["ball","football","rugby","sports","team"]},"tennis":{"a":"Tennis","b":"1F3BE","j":["ball","racquet","sports","balls","green"]},"flying-disc":{"a":"Flying Disc","b":"1F94F","j":["ultimate","sports","frisbee"]},"bowling":{"a":"Bowling","b":"1F3B3","j":["ball","game","sports","fun","play"]},"cricket-game":{"a":"Cricket Game","b":"1F3CF","j":["ball","bat","game","sports"]},"field-hockey":{"a":"Field Hockey","b":"1F3D1","j":["ball","field","game","hockey","stick","sports"]},"ice-hockey":{"a":"Ice Hockey","b":"1F3D2","j":["game","hockey","ice","puck","stick","sports"]},"lacrosse":{"a":"Lacrosse","b":"1F94D","j":["ball","goal","stick","sports"]},"ping-pong":{"a":"Ping Pong","b":"1F3D3","j":["ball","bat","game","paddle","table tennis","sports","pingpong"]},"badminton":{"a":"Badminton","b":"1F3F8","j":["birdie","game","racquet","shuttlecock","sports"]},"boxing-glove":{"a":"Boxing Glove","b":"1F94A","j":["boxing","glove","sports","fighting"]},"martial-arts-uniform":{"a":"Martial Arts Uniform","b":"1F94B","j":["judo","karate","martial arts","taekwondo","uniform"]},"goal-net":{"a":"Goal Net","b":"1F945","j":["goal","net","sports"]},"flag-in-hole":{"a":"Flag in Hole","b":"26F3","j":["golf","hole","sports","business","flag","summer"]},"ice-skate":{"a":"Ice Skate","b":"26F8","j":["ice","skate","sports"]},"fishing-pole":{"a":"Fishing Pole","b":"1F3A3","j":["fish","pole","food","hobby","summer"]},"diving-mask":{"a":"Diving Mask","b":"1F93F","j":["diving","scuba","snorkeling","sport","ocean"]},"running-shirt":{"a":"Running Shirt","b":"1F3BD","j":["athletics","running","sash","shirt","play","pageant"]},"skis":{"a":"Skis","b":"1F3BF","j":["ski","snow","sports","winter","cold"]},"sled":{"a":"Sled","b":"1F6F7","j":["sledge","sleigh","luge","toboggan"]},"curling-stone":{"a":"Curling Stone","b":"1F94C","j":["game","rock","sports"]},"bullseye":{"a":"Bullseye","b":"1F3AF","j":["dart","direct hit","game","hit","target","direct_hit","play","bar"]},"yoyo":{"a":"Yo-Yo","b":"1FA80","j":["fluctuate","toy","yo-yo","yo_yo"]},"kite":{"a":"Kite","b":"1FA81","j":["fly","soar","wind"]},"pool-8-ball":{"a":"Pool 8 Ball","b":"1F3B1","j":["8","ball","billiard","eight","game","pool","hobby","luck","magic"]},"crystal-ball":{"a":"Crystal Ball","b":"1F52E","j":["ball","crystal","fairy tale","fantasy","fortune","tool","disco","party","magic","circus","fortune_teller"]},"magic-wand":{"a":"Magic Wand","b":"1FA84","j":["magic","witch","wizard","supernature","power"]},"nazar-amulet":{"a":"Nazar Amulet","b":"1F9FF","j":["bead","charm","evil-eye","nazar","talisman"]},"hamsa":{"a":"⊛ Hamsa","b":"1FAAC","j":["amulet","Fatima","hand","Mary","Miriam","protection"]},"video-game":{"a":"Video Game","b":"1F3AE","j":["controller","game","play","console","PS4"]},"joystick":{"a":"Joystick","b":"1F579","j":["game","video game","play"]},"slot-machine":{"a":"Slot Machine","b":"1F3B0","j":["game","slot","bet","gamble","vegas","fruit machine","luck","casino"]},"game-die":{"a":"Game Die","b":"1F3B2","j":["dice","die","game","random","tabletop","play","luck"]},"puzzle-piece":{"a":"Puzzle Piece","b":"1F9E9","j":["clue","interlocking","jigsaw","piece","puzzle"]},"teddy-bear":{"a":"Teddy Bear","b":"1F9F8","j":["plaything","plush","stuffed","toy"]},"piata":{"a":"Piñata","b":"1FA85","j":["celebration","party","piñata","pinata","mexico","candy"]},"mirror-ball":{"a":"⊛ Mirror Ball","b":"1FAA9","j":["dance","disco","glitter","party"]},"nesting-dolls":{"a":"Nesting Dolls","b":"1FA86","j":["doll","nesting","russia","matryoshka","toy"]},"spade-suit":{"a":"Spade Suit","b":"2660","j":["card","game","poker","cards","suits","magic"]},"heart-suit":{"a":"Heart Suit","b":"2665","j":["card","game","poker","cards","magic","suits"]},"diamond-suit":{"a":"Diamond Suit","b":"2666","j":["card","game","poker","cards","magic","suits"]},"club-suit":{"a":"Club Suit","b":"2663","j":["card","game","poker","cards","magic","suits"]},"chess-pawn":{"a":"Chess Pawn","b":"265F","j":["chess","dupe","expendable"]},"joker":{"a":"Joker","b":"1F0CF","j":["card","game","wildcard","poker","cards","play","magic"]},"mahjong-red-dragon":{"a":"Mahjong Red Dragon","b":"1F004","j":["game","mahjong","red","play","chinese","kanji"]},"flower-playing-cards":{"a":"Flower Playing Cards","b":"1F3B4","j":["card","flower","game","Japanese","playing","sunset","red"]},"performing-arts":{"a":"Performing Arts","b":"1F3AD","j":["art","mask","performing","theater","theatre","acting","drama"]},"framed-picture":{"a":"Framed Picture","b":"1F5BC","j":["art","frame","museum","painting","picture","photography"]},"artist-palette":{"a":"Artist Palette","b":"1F3A8","j":["art","museum","painting","palette","design","paint","draw","colors"]},"thread":{"a":"Thread","b":"1F9F5","j":["needle","sewing","spool","string"]},"sewing-needle":{"a":"Sewing Needle","b":"1FAA1","j":["embroidery","needle","sewing","stitches","sutures","tailoring"]},"yarn":{"a":"Yarn","b":"1F9F6","j":["ball","crochet","knit"]},"knot":{"a":"Knot","b":"1FAA2","j":["rope","tangled","tie","twine","twist","scout"]},"glasses":{"a":"Glasses","b":"1F453","j":["clothing","eye","eyeglasses","eyewear","fashion","accessories","eyesight","nerdy","dork","geek"]},"sunglasses":{"a":"Sunglasses","b":"1F576","j":["dark","eye","eyewear","glasses","face","cool","accessories"]},"goggles":{"a":"Goggles","b":"1F97D","j":["eye protection","swimming","welding","eyes","protection","safety"]},"lab-coat":{"a":"Lab Coat","b":"1F97C","j":["doctor","experiment","scientist","chemist"]},"safety-vest":{"a":"Safety Vest","b":"1F9BA","j":["emergency","safety","vest","protection"]},"necktie":{"a":"Necktie","b":"1F454","j":["clothing","tie","shirt","suitup","formal","fashion","cloth","business"]},"tshirt":{"a":"T-Shirt","b":"1F455","j":["clothing","shirt","t-shirt","t_shirt","fashion","cloth","casual","tee"]},"jeans":{"a":"Jeans","b":"1F456","j":["clothing","pants","trousers","fashion","shopping"]},"scarf":{"a":"Scarf","b":"1F9E3","j":["neck","winter","clothes"]},"gloves":{"a":"Gloves","b":"1F9E4","j":["hand","hands","winter","clothes"]},"coat":{"a":"Coat","b":"1F9E5","j":["jacket"]},"socks":{"a":"Socks","b":"1F9E6","j":["stocking","stockings","clothes"]},"dress":{"a":"Dress","b":"1F457","j":["clothing","clothes","fashion","shopping"]},"kimono":{"a":"Kimono","b":"1F458","j":["clothing","dress","fashion","women","female","japanese"]},"sari":{"a":"Sari","b":"1F97B","j":["clothing","dress"]},"onepiece-swimsuit":{"a":"One-Piece Swimsuit","b":"1FA71","j":["bathing suit","one-piece swimsuit","one_piece_swimsuit","fashion"]},"briefs":{"a":"Briefs","b":"1FA72","j":["bathing suit","one-piece","swimsuit","underwear","clothing"]},"shorts":{"a":"Shorts","b":"1FA73","j":["bathing suit","pants","underwear","clothing"]},"bikini":{"a":"Bikini","b":"1F459","j":["clothing","swim","swimming","female","woman","girl","fashion","beach","summer"]},"womans-clothes":{"a":"Woman’S Clothes","b":"1F45A","j":["clothing","woman","woman’s clothes","woman_s_clothes","fashion","shopping_bags","female"]},"purse":{"a":"Purse","b":"1F45B","j":["clothing","coin","fashion","accessories","money","sales","shopping"]},"handbag":{"a":"Handbag","b":"1F45C","j":["bag","clothing","purse","fashion","accessory","accessories","shopping"]},"clutch-bag":{"a":"Clutch Bag","b":"1F45D","j":["bag","clothing","pouch","accessories","shopping"]},"shopping-bags":{"a":"Shopping Bags","b":"1F6CD","j":["bag","hotel","shopping","mall","buy","purchase"]},"backpack":{"a":"Backpack","b":"1F392","j":["bag","rucksack","satchel","school","student","education"]},"thong-sandal":{"a":"Thong Sandal","b":"1FA74","j":["beach sandals","sandals","thong sandals","thongs","zōri","footwear","summer"]},"mans-shoe":{"a":"Man’S Shoe","b":"1F45E","j":["clothing","man","man’s shoe","shoe","man_s_shoe","fashion","male"]},"running-shoe":{"a":"Running Shoe","b":"1F45F","j":["athletic","clothing","shoe","sneaker","shoes","sports","sneakers"]},"hiking-boot":{"a":"Hiking Boot","b":"1F97E","j":["backpacking","boot","camping","hiking"]},"flat-shoe":{"a":"Flat Shoe","b":"1F97F","j":["ballet flat","slip-on","slipper","ballet"]},"highheeled-shoe":{"a":"High-Heeled Shoe","b":"1F460","j":["clothing","heel","high-heeled shoe","shoe","woman","high_heeled_shoe","fashion","shoes","female","pumps","stiletto"]},"womans-sandal":{"a":"Woman’S Sandal","b":"1F461","j":["clothing","sandal","shoe","woman","woman’s sandal","woman_s_sandal","shoes","fashion","flip flops"]},"ballet-shoes":{"a":"Ballet Shoes","b":"1FA70","j":["ballet","dance"]},"womans-boot":{"a":"Woman’S Boot","b":"1F462","j":["boot","clothing","shoe","woman","woman’s boot","woman_s_boot","shoes","fashion"]},"crown":{"a":"Crown","b":"1F451","j":["clothing","king","queen","kod","leader","royalty","lord"]},"womans-hat":{"a":"Woman’S Hat","b":"1F452","j":["clothing","hat","woman","woman’s hat","woman_s_hat","fashion","accessories","female","lady","spring"]},"top-hat":{"a":"Top Hat","b":"1F3A9","j":["clothing","hat","top","tophat","magic","gentleman","classy","circus"]},"graduation-cap":{"a":"Graduation Cap","b":"1F393","j":["cap","celebration","clothing","graduation","hat","school","college","degree","university","legal","learn","education"]},"billed-cap":{"a":"Billed Cap","b":"1F9E2","j":["baseball cap","cap","baseball"]},"military-helmet":{"a":"Military Helmet","b":"1FA96","j":["army","helmet","military","soldier","warrior","protection"]},"rescue-workers-helmet":{"a":"Rescue Worker’S Helmet","b":"26D1","j":["aid","cross","face","hat","helmet","rescue worker’s helmet","rescue_worker_s_helmet","construction","build"]},"prayer-beads":{"a":"Prayer Beads","b":"1F4FF","j":["beads","clothing","necklace","prayer","religion","dhikr","religious"]},"lipstick":{"a":"Lipstick","b":"1F484","j":["cosmetics","makeup","female","girl","fashion","woman"]},"ring":{"a":"Ring","b":"1F48D","j":["diamond","wedding","propose","marriage","valentines","fashion","jewelry","gem","engagement"]},"gem-stone":{"a":"Gem Stone","b":"1F48E","j":["diamond","gem","jewel","blue","ruby","jewelry"]},"muted-speaker":{"a":"Muted Speaker","b":"1F507","j":["mute","quiet","silent","speaker","sound","volume","silence"]},"speaker-low-volume":{"a":"Speaker Low Volume","b":"1F508","j":["soft","sound","volume","silence","broadcast"]},"speaker-medium-volume":{"a":"Speaker Medium Volume","b":"1F509","j":["medium","volume","speaker","broadcast"]},"speaker-high-volume":{"a":"Speaker High Volume","b":"1F50A","j":["loud","volume","noise","noisy","speaker","broadcast"]},"loudspeaker":{"a":"Loudspeaker","b":"1F4E2","j":["loud","public address","volume","sound"]},"megaphone":{"a":"Megaphone","b":"1F4E3","j":["cheering","sound","speaker","volume"]},"postal-horn":{"a":"Postal Horn","b":"1F4EF","j":["horn","post","postal","instrument","music"]},"bell":{"a":"Bell","b":"1F514","j":["sound","notification","christmas","xmas","chime"]},"bell-with-slash":{"a":"Bell with Slash","b":"1F515","j":["bell","forbidden","mute","quiet","silent","sound","volume"]},"musical-score":{"a":"Musical Score","b":"1F3BC","j":["music","score","treble","clef","compose"]},"musical-note":{"a":"Musical Note","b":"1F3B5","j":["music","note","score","tone","sound"]},"musical-notes":{"a":"Musical Notes","b":"1F3B6","j":["music","note","notes","score"]},"studio-microphone":{"a":"Studio Microphone","b":"1F399","j":["mic","microphone","music","studio","sing","recording","artist","talkshow"]},"level-slider":{"a":"Level Slider","b":"1F39A","j":["level","music","slider","scale"]},"control-knobs":{"a":"Control Knobs","b":"1F39B","j":["control","knobs","music","dial"]},"microphone":{"a":"Microphone","b":"1F3A4","j":["karaoke","mic","sound","music","PA","sing","talkshow"]},"headphone":{"a":"Headphone","b":"1F3A7","j":["earbud","music","score","gadgets"]},"radio":{"a":"Radio","b":"1F4FB","j":["video","communication","music","podcast","program"]},"saxophone":{"a":"Saxophone","b":"1F3B7","j":["instrument","music","sax","jazz","blues"]},"accordion":{"a":"Accordion","b":"1FA97","j":["concertina","squeeze box","music"]},"guitar":{"a":"Guitar","b":"1F3B8","j":["instrument","music"]},"musical-keyboard":{"a":"Musical Keyboard","b":"1F3B9","j":["instrument","keyboard","music","piano","compose"]},"trumpet":{"a":"Trumpet","b":"1F3BA","j":["instrument","music","brass"]},"violin":{"a":"Violin","b":"1F3BB","j":["instrument","music","orchestra","symphony"]},"banjo":{"a":"Banjo","b":"1FA95","j":["music","stringed","instructment"]},"drum":{"a":"Drum","b":"1F941","j":["drumsticks","music","instrument","snare"]},"long-drum":{"a":"Long Drum","b":"1FA98","j":["beat","conga","drum","rhythm","music"]},"mobile-phone":{"a":"Mobile Phone","b":"1F4F1","j":["cell","mobile","phone","telephone","technology","apple","gadgets","dial"]},"mobile-phone-with-arrow":{"a":"Mobile Phone with Arrow","b":"1F4F2","j":["arrow","cell","mobile","phone","receive","iphone","incoming"]},"telephone":{"a":"Telephone","b":"260E","j":["phone","technology","communication","dial"]},"telephone-receiver":{"a":"Telephone Receiver","b":"1F4DE","j":["phone","receiver","telephone","technology","communication","dial"]},"pager":{"a":"Pager","b":"1F4DF","j":["bbcall","oldschool","90s"]},"fax-machine":{"a":"Fax Machine","b":"1F4E0","j":["fax","communication","technology"]},"battery":{"a":"Battery","b":"1F50B","j":["power","energy","sustain"]},"low-battery":{"a":"⊛ Low Battery","b":"1FAAB","j":["electronic","low energy"]},"electric-plug":{"a":"Electric Plug","b":"1F50C","j":["electric","electricity","plug","charger","power"]},"laptop":{"a":"Laptop","b":"1F4BB","j":["computer","pc","personal","technology","screen","display","monitor"]},"desktop-computer":{"a":"Desktop Computer","b":"1F5A5","j":["computer","desktop","technology","computing","screen"]},"printer":{"a":"Printer","b":"1F5A8","j":["computer","paper","ink"]},"keyboard":{"a":"Keyboard","b":"2328","j":["computer","technology","type","input","text"]},"computer-mouse":{"a":"Computer Mouse","b":"1F5B1","j":["computer","click"]},"trackball":{"a":"Trackball","b":"1F5B2","j":["computer","technology","trackpad"]},"computer-disk":{"a":"Computer Disk","b":"1F4BD","j":["computer","disk","minidisk","optical","technology","record","data","90s"]},"floppy-disk":{"a":"Floppy Disk","b":"1F4BE","j":["computer","disk","floppy","oldschool","technology","save","90s","80s"]},"optical-disk":{"a":"Optical Disk","b":"1F4BF","j":["cd","computer","disk","optical","technology","dvd","disc","90s"]},"dvd":{"a":"Dvd","b":"1F4C0","j":["blu-ray","computer","disk","optical","cd","disc"]},"abacus":{"a":"Abacus","b":"1F9EE","j":["calculation"]},"movie-camera":{"a":"Movie Camera","b":"1F3A5","j":["camera","cinema","movie","film","record"]},"film-frames":{"a":"Film Frames","b":"1F39E","j":["cinema","film","frames","movie"]},"film-projector":{"a":"Film Projector","b":"1F4FD","j":["cinema","film","movie","projector","video","tape","record"]},"clapper-board":{"a":"Clapper Board","b":"1F3AC","j":["clapper","movie","film","record"]},"television":{"a":"Television","b":"1F4FA","j":["tv","video","technology","program","oldschool","show"]},"camera":{"a":"Camera","b":"1F4F7","j":["video","gadgets","photography"]},"camera-with-flash":{"a":"Camera with Flash","b":"1F4F8","j":["camera","flash","video","photography","gadgets"]},"video-camera":{"a":"Video Camera","b":"1F4F9","j":["camera","video","film","record"]},"videocassette":{"a":"Videocassette","b":"1F4FC","j":["tape","vhs","video","record","oldschool","90s","80s"]},"magnifying-glass-tilted-left":{"a":"Magnifying Glass Tilted Left","b":"1F50D","j":["glass","magnifying","search","tool","zoom","find","detective"]},"magnifying-glass-tilted-right":{"a":"Magnifying Glass Tilted Right","b":"1F50E","j":["glass","magnifying","search","tool","zoom","find","detective"]},"candle":{"a":"Candle","b":"1F56F","j":["light","fire","wax"]},"light-bulb":{"a":"Light Bulb","b":"1F4A1","j":["bulb","comic","electric","idea","light","electricity"]},"flashlight":{"a":"Flashlight","b":"1F526","j":["electric","light","tool","torch","dark","camping","sight","night"]},"red-paper-lantern":{"a":"Red Paper Lantern","b":"1F3EE","j":["bar","lantern","light","red","paper","halloween","spooky"]},"diya-lamp":{"a":"Diya Lamp","b":"1FA94","j":["diya","lamp","oil","lighting"]},"notebook-with-decorative-cover":{"a":"Notebook with Decorative Cover","b":"1F4D4","j":["book","cover","decorated","notebook","classroom","notes","record","paper","study"]},"closed-book":{"a":"Closed Book","b":"1F4D5","j":["book","closed","read","library","knowledge","textbook","learn"]},"open-book":{"a":"Open Book","b":"1F4D6","j":["book","open","read","library","knowledge","literature","learn","study"]},"green-book":{"a":"Green Book","b":"1F4D7","j":["book","green","read","library","knowledge","study"]},"blue-book":{"a":"Blue Book","b":"1F4D8","j":["blue","book","read","library","knowledge","learn","study"]},"orange-book":{"a":"Orange Book","b":"1F4D9","j":["book","orange","read","library","knowledge","textbook","study"]},"books":{"a":"Books","b":"1F4DA","j":["book","literature","library","study"]},"notebook":{"a":"Notebook","b":"1F4D3","j":["stationery","record","notes","paper","study"]},"ledger":{"a":"Ledger","b":"1F4D2","j":["notebook","notes","paper"]},"page-with-curl":{"a":"Page with Curl","b":"1F4C3","j":["curl","document","page","documents","office","paper"]},"scroll":{"a":"Scroll","b":"1F4DC","j":["paper","documents","ancient","history"]},"page-facing-up":{"a":"Page Facing Up","b":"1F4C4","j":["document","page","documents","office","paper","information"]},"newspaper":{"a":"Newspaper","b":"1F4F0","j":["news","paper","press","headline"]},"rolledup-newspaper":{"a":"Rolled-Up Newspaper","b":"1F5DE","j":["news","newspaper","paper","rolled","rolled-up newspaper","rolled_up_newspaper","press","headline"]},"bookmark-tabs":{"a":"Bookmark Tabs","b":"1F4D1","j":["bookmark","mark","marker","tabs","favorite","save","order","tidy"]},"bookmark":{"a":"Bookmark","b":"1F516","j":["mark","favorite","label","save"]},"label":{"a":"Label","b":"1F3F7","j":["sale","tag"]},"money-bag":{"a":"Money Bag","b":"1F4B0","j":["bag","dollar","money","moneybag","payment","coins","sale"]},"coin":{"a":"Coin","b":"1FA99","j":["gold","metal","money","silver","treasure","currency"]},"yen-banknote":{"a":"Yen Banknote","b":"1F4B4","j":["banknote","bill","currency","money","note","yen","sales","japanese","dollar"]},"dollar-banknote":{"a":"Dollar Banknote","b":"1F4B5","j":["banknote","bill","currency","dollar","money","note","sales"]},"euro-banknote":{"a":"Euro Banknote","b":"1F4B6","j":["banknote","bill","currency","euro","money","note","sales","dollar"]},"pound-banknote":{"a":"Pound Banknote","b":"1F4B7","j":["banknote","bill","currency","money","note","pound","british","sterling","sales","bills","uk","england"]},"money-with-wings":{"a":"Money with Wings","b":"1F4B8","j":["banknote","bill","fly","money","wings","dollar","bills","payment","sale"]},"credit-card":{"a":"Credit Card","b":"1F4B3","j":["card","credit","money","sales","dollar","bill","payment","shopping"]},"receipt":{"a":"Receipt","b":"1F9FE","j":["accounting","bookkeeping","evidence","proof","expenses"]},"chart-increasing-with-yen":{"a":"Chart Increasing with Yen","b":"1F4B9","j":["chart","graph","growth","money","yen","green-square","presentation","stats"]},"envelope":{"a":"Envelope","b":"2709","j":["email","letter","postal","inbox","communication"]},"email":{"a":"E-Mail","b":"1F4E7","j":["e-mail","letter","mail","e_mail","communication","inbox"]},"incoming-envelope":{"a":"Incoming Envelope","b":"1F4E8","j":["e-mail","email","envelope","incoming","letter","receive","inbox"]},"envelope-with-arrow":{"a":"Envelope with Arrow","b":"1F4E9","j":["arrow","e-mail","email","envelope","outgoing","communication"]},"outbox-tray":{"a":"Outbox Tray","b":"1F4E4","j":["box","letter","mail","outbox","sent","tray","inbox","email"]},"inbox-tray":{"a":"Inbox Tray","b":"1F4E5","j":["box","inbox","letter","mail","receive","tray","email","documents"]},"package":{"a":"Package","b":"1F4E6","j":["box","parcel","mail","gift","cardboard","moving"]},"closed-mailbox-with-raised-flag":{"a":"Closed Mailbox with Raised Flag","b":"1F4EB","j":["closed","mail","mailbox","postbox","email","inbox","communication"]},"closed-mailbox-with-lowered-flag":{"a":"Closed Mailbox with Lowered Flag","b":"1F4EA","j":["closed","lowered","mail","mailbox","postbox","email","communication","inbox"]},"open-mailbox-with-raised-flag":{"a":"Open Mailbox with Raised Flag","b":"1F4EC","j":["mail","mailbox","open","postbox","email","inbox","communication"]},"open-mailbox-with-lowered-flag":{"a":"Open Mailbox with Lowered Flag","b":"1F4ED","j":["lowered","mail","mailbox","open","postbox","email","inbox"]},"postbox":{"a":"Postbox","b":"1F4EE","j":["mail","mailbox","email","letter","envelope"]},"ballot-box-with-ballot":{"a":"Ballot Box with Ballot","b":"1F5F3","j":["ballot","box","election","vote"]},"pencil":{"a":"Pencil","b":"270F","j":["stationery","write","paper","writing","school","study"]},"black-nib":{"a":"Black Nib","b":"2712","j":["nib","pen","stationery","writing","write"]},"fountain-pen":{"a":"Fountain Pen","b":"1F58B","j":["fountain","pen","stationery","writing","write"]},"pen":{"a":"Pen","b":"1F58A","j":["ballpoint","stationery","writing","write"]},"paintbrush":{"a":"Paintbrush","b":"1F58C","j":["painting","drawing","creativity","art"]},"crayon":{"a":"Crayon","b":"1F58D","j":["drawing","creativity"]},"memo":{"a":"Memo","b":"1F4DD","j":["pencil","write","documents","stationery","paper","writing","legal","exam","quiz","test","study","compose"]},"briefcase":{"a":"Briefcase","b":"1F4BC","j":["business","documents","work","law","legal","job","career"]},"file-folder":{"a":"File Folder","b":"1F4C1","j":["file","folder","documents","business","office"]},"open-file-folder":{"a":"Open File Folder","b":"1F4C2","j":["file","folder","open","documents","load"]},"card-index-dividers":{"a":"Card Index Dividers","b":"1F5C2","j":["card","dividers","index","organizing","business","stationery"]},"calendar":{"a":"Calendar","b":"1F4C5","j":["date","schedule"]},"tearoff-calendar":{"a":"Tear-off Calendar","b":"1F4C6","j":["calendar","tear-off calendar","tear_off_calendar","schedule","date","planning"]},"spiral-notepad":{"a":"Spiral Notepad","b":"1F5D2","j":["note","pad","spiral","memo","stationery"]},"spiral-calendar":{"a":"Spiral Calendar","b":"1F5D3","j":["calendar","pad","spiral","date","schedule","planning"]},"card-index":{"a":"Card Index","b":"1F4C7","j":["card","index","rolodex","business","stationery"]},"chart-increasing":{"a":"Chart Increasing","b":"1F4C8","j":["chart","graph","growth","trend","upward","presentation","stats","recovery","business","economics","money","sales","good","success"]},"chart-decreasing":{"a":"Chart Decreasing","b":"1F4C9","j":["chart","down","graph","trend","presentation","stats","recession","business","economics","money","sales","bad","failure"]},"bar-chart":{"a":"Bar Chart","b":"1F4CA","j":["bar","chart","graph","presentation","stats"]},"clipboard":{"a":"Clipboard","b":"1F4CB","j":["stationery","documents"]},"pushpin":{"a":"Pushpin","b":"1F4CC","j":["pin","stationery","mark","here"]},"round-pushpin":{"a":"Round Pushpin","b":"1F4CD","j":["pin","pushpin","stationery","location","map","here"]},"paperclip":{"a":"Paperclip","b":"1F4CE","j":["documents","stationery"]},"linked-paperclips":{"a":"Linked Paperclips","b":"1F587","j":["link","paperclip","documents","stationery"]},"straight-ruler":{"a":"Straight Ruler","b":"1F4CF","j":["ruler","straight edge","stationery","calculate","length","math","school","drawing","architect","sketch"]},"triangular-ruler":{"a":"Triangular Ruler","b":"1F4D0","j":["ruler","set","triangle","stationery","math","architect","sketch"]},"scissors":{"a":"Scissors","b":"2702","j":["cutting","tool","stationery","cut"]},"card-file-box":{"a":"Card File Box","b":"1F5C3","j":["box","card","file","business","stationery"]},"file-cabinet":{"a":"File Cabinet","b":"1F5C4","j":["cabinet","file","filing","organizing"]},"wastebasket":{"a":"Wastebasket","b":"1F5D1","j":["bin","trash","rubbish","garbage","toss"]},"locked":{"a":"Locked","b":"1F512","j":["closed","security","password","padlock"]},"unlocked":{"a":"Unlocked","b":"1F513","j":["lock","open","unlock","privacy","security"]},"locked-with-pen":{"a":"Locked with Pen","b":"1F50F","j":["ink","lock","nib","pen","privacy","security","secret"]},"locked-with-key":{"a":"Locked with Key","b":"1F510","j":["closed","key","lock","secure","security","privacy"]},"key":{"a":"Key","b":"1F511","j":["lock","password","door"]},"old-key":{"a":"Old Key","b":"1F5DD","j":["clue","key","lock","old","door","password"]},"hammer":{"a":"Hammer","b":"1F528","j":["tool","tools","build","create"]},"axe":{"a":"Axe","b":"1FA93","j":["chop","hatchet","split","wood","tool","cut"]},"pick":{"a":"Pick","b":"26CF","j":["mining","tool","tools","dig"]},"hammer-and-pick":{"a":"Hammer and Pick","b":"2692","j":["hammer","pick","tool","tools","build","create"]},"hammer-and-wrench":{"a":"Hammer and Wrench","b":"1F6E0","j":["hammer","spanner","tool","wrench","tools","build","create"]},"dagger":{"a":"Dagger","b":"1F5E1","j":["knife","weapon"]},"crossed-swords":{"a":"Crossed Swords","b":"2694","j":["crossed","swords","weapon"]},"water-pistol":{"a":"Water Pistol","b":"1F52B","j":["gun","handgun","pistol","revolver","tool","water","weapon","violence"]},"boomerang":{"a":"Boomerang","b":"1FA83","j":["australia","rebound","repercussion","weapon"]},"bow-and-arrow":{"a":"Bow and Arrow","b":"1F3F9","j":["archer","arrow","bow","Sagittarius","zodiac","sports"]},"shield":{"a":"Shield","b":"1F6E1","j":["weapon","protection","security"]},"carpentry-saw":{"a":"Carpentry Saw","b":"1FA9A","j":["carpenter","lumber","saw","tool","cut","chop"]},"wrench":{"a":"Wrench","b":"1F527","j":["spanner","tool","tools","diy","ikea","fix","maintainer"]},"screwdriver":{"a":"Screwdriver","b":"1FA9B","j":["screw","tool","tools"]},"nut-and-bolt":{"a":"Nut and Bolt","b":"1F529","j":["bolt","nut","tool","handy","tools","fix"]},"gear":{"a":"Gear","b":"2699","j":["cog","cogwheel","tool"]},"clamp":{"a":"Clamp","b":"1F5DC","j":["compress","tool","vice"]},"balance-scale":{"a":"Balance Scale","b":"2696","j":["balance","justice","Libra","scale","zodiac","law","fairness","weight"]},"white-cane":{"a":"White Cane","b":"1F9AF","j":["accessibility","blind","probing_cane"]},"link":{"a":"Link","b":"1F517","j":["rings","url"]},"chains":{"a":"Chains","b":"26D3","j":["chain","lock","arrest"]},"hook":{"a":"Hook","b":"1FA9D","j":["catch","crook","curve","ensnare","selling point","tools"]},"toolbox":{"a":"Toolbox","b":"1F9F0","j":["chest","mechanic","tool","tools","diy","fix","maintainer"]},"magnet":{"a":"Magnet","b":"1F9F2","j":["attraction","horseshoe","magnetic"]},"ladder":{"a":"Ladder","b":"1FA9C","j":["climb","rung","step","tools"]},"alembic":{"a":"Alembic","b":"2697","j":["chemistry","tool","distilling","science","experiment"]},"test-tube":{"a":"Test Tube","b":"1F9EA","j":["chemist","chemistry","experiment","lab","science"]},"petri-dish":{"a":"Petri Dish","b":"1F9EB","j":["bacteria","biologist","biology","culture","lab"]},"dna":{"a":"Dna","b":"1F9EC","j":["biologist","evolution","gene","genetics","life"]},"microscope":{"a":"Microscope","b":"1F52C","j":["science","tool","laboratory","experiment","zoomin","study"]},"telescope":{"a":"Telescope","b":"1F52D","j":["science","tool","stars","space","zoom","astronomy"]},"satellite-antenna":{"a":"Satellite Antenna","b":"1F4E1","j":["antenna","dish","satellite","communication","future","radio","space"]},"syringe":{"a":"Syringe","b":"1F489","j":["medicine","needle","shot","sick","health","hospital","drugs","blood","doctor","nurse"]},"drop-of-blood":{"a":"Drop of Blood","b":"1FA78","j":["bleed","blood donation","injury","medicine","menstruation","period","hurt","harm","wound"]},"pill":{"a":"Pill","b":"1F48A","j":["doctor","medicine","sick","health","pharmacy","drug"]},"adhesive-bandage":{"a":"Adhesive Bandage","b":"1FA79","j":["bandage","heal"]},"crutch":{"a":"⊛ Crutch","b":"1FA7C","j":["cane","disability","hurt","mobility aid","stick"]},"stethoscope":{"a":"Stethoscope","b":"1FA7A","j":["doctor","heart","medicine","health"]},"xray":{"a":"⊛ X-Ray","b":"1FA7B","j":["bones","doctor","medical","skeleton"]},"door":{"a":"Door","b":"1F6AA","j":["house","entry","exit"]},"elevator":{"a":"Elevator","b":"1F6D7","j":["accessibility","hoist","lift"]},"mirror":{"a":"Mirror","b":"1FA9E","j":["reflection","reflector","speculum"]},"window":{"a":"Window","b":"1FA9F","j":["frame","fresh air","opening","transparent","view","scenery"]},"bed":{"a":"Bed","b":"1F6CF","j":["hotel","sleep","rest"]},"couch-and-lamp":{"a":"Couch and Lamp","b":"1F6CB","j":["couch","hotel","lamp","read","chill"]},"chair":{"a":"Chair","b":"1FA91","j":["seat","sit","furniture"]},"toilet":{"a":"Toilet","b":"1F6BD","j":["restroom","wc","washroom","bathroom","potty"]},"plunger":{"a":"Plunger","b":"1FAA0","j":["force cup","plumber","suction","toilet"]},"shower":{"a":"Shower","b":"1F6BF","j":["water","clean","bathroom"]},"bathtub":{"a":"Bathtub","b":"1F6C1","j":["bath","clean","shower","bathroom"]},"mouse-trap":{"a":"Mouse Trap","b":"1FAA4","j":["bait","mousetrap","snare","trap","cheese"]},"razor":{"a":"Razor","b":"1FA92","j":["sharp","shave","cut"]},"lotion-bottle":{"a":"Lotion Bottle","b":"1F9F4","j":["lotion","moisturizer","shampoo","sunscreen"]},"safety-pin":{"a":"Safety Pin","b":"1F9F7","j":["diaper","punk rock"]},"broom":{"a":"Broom","b":"1F9F9","j":["cleaning","sweeping","witch"]},"basket":{"a":"Basket","b":"1F9FA","j":["farming","laundry","picnic"]},"roll-of-paper":{"a":"Roll of Paper","b":"1F9FB","j":["paper towels","toilet paper","roll"]},"bucket":{"a":"Bucket","b":"1FAA3","j":["cask","pail","vat","water","container"]},"soap":{"a":"Soap","b":"1F9FC","j":["bar","bathing","cleaning","lather","soapdish"]},"bubbles":{"a":"⊛ Bubbles","b":"1FAE7","j":["burp","clean","soap","underwater"]},"toothbrush":{"a":"Toothbrush","b":"1FAA5","j":["bathroom","brush","clean","dental","hygiene","teeth"]},"sponge":{"a":"Sponge","b":"1F9FD","j":["absorbing","cleaning","porous"]},"fire-extinguisher":{"a":"Fire Extinguisher","b":"1F9EF","j":["extinguish","fire","quench"]},"shopping-cart":{"a":"Shopping Cart","b":"1F6D2","j":["cart","shopping","trolley"]},"cigarette":{"a":"Cigarette","b":"1F6AC","j":["smoking","kills","tobacco","joint","smoke"]},"coffin":{"a":"Coffin","b":"26B0","j":["death","vampire","dead","die","rip","graveyard","cemetery","casket","funeral","box"]},"headstone":{"a":"Headstone","b":"1FAA6","j":["cemetery","grave","graveyard","tombstone","death","rip"]},"funeral-urn":{"a":"Funeral Urn","b":"26B1","j":["ashes","death","funeral","urn","dead","die","rip"]},"moai":{"a":"Moai","b":"1F5FF","j":["face","moyai","statue","rock","easter island"]},"placard":{"a":"Placard","b":"1FAA7","j":["demonstration","picket","protest","sign","announcement"]},"identification-card":{"a":"⊛ Identification Card","b":"1FAAA","j":["credentials","ID","license","security"]},"atm-sign":{"a":"Atm Sign","b":"1F3E7","j":["atm","ATM sign","automated","bank","teller","money","sales","cash","blue-square","payment"]},"litter-in-bin-sign":{"a":"Litter in Bin Sign","b":"1F6AE","j":["litter","litter bin","blue-square","sign","human","info"]},"potable-water":{"a":"Potable Water","b":"1F6B0","j":["drinking","potable","water","blue-square","liquid","restroom","cleaning","faucet"]},"wheelchair-symbol":{"a":"Wheelchair Symbol","b":"267F","j":["access","blue-square","disabled","accessibility"]},"mens-room":{"a":"Men’S Room","b":"1F6B9","j":["lavatory","man","men’s room","restroom","wc","men_s_room","toilet","blue-square","gender","male"]},"womens-room":{"a":"Women’S Room","b":"1F6BA","j":["lavatory","restroom","wc","woman","women’s room","women_s_room","purple-square","female","toilet","loo","gender"]},"restroom":{"a":"Restroom","b":"1F6BB","j":["lavatory","WC","blue-square","toilet","refresh","wc","gender"]},"baby-symbol":{"a":"Baby Symbol","b":"1F6BC","j":["baby","changing","orange-square","child"]},"water-closet":{"a":"Water Closet","b":"1F6BE","j":["closet","lavatory","restroom","water","wc","toilet","blue-square"]},"passport-control":{"a":"Passport Control","b":"1F6C2","j":["control","passport","custom","blue-square"]},"customs":{"a":"Customs","b":"1F6C3","j":["passport","border","blue-square"]},"baggage-claim":{"a":"Baggage Claim","b":"1F6C4","j":["baggage","claim","blue-square","airport","transport"]},"left-luggage":{"a":"Left Luggage","b":"1F6C5","j":["baggage","locker","luggage","blue-square","travel"]},"warning":{"a":"Warning","b":"26A0","j":["exclamation","wip","alert","error","problem","issue"]},"children-crossing":{"a":"Children Crossing","b":"1F6B8","j":["child","crossing","pedestrian","traffic","school","warning","danger","sign","driving","yellow-diamond"]},"no-entry":{"a":"No Entry","b":"26D4","j":["entry","forbidden","no","not","prohibited","traffic","limit","security","privacy","bad","denied","stop","circle"]},"prohibited":{"a":"Prohibited","b":"1F6AB","j":["entry","forbidden","no","not","forbid","stop","limit","denied","disallow","circle"]},"no-bicycles":{"a":"No Bicycles","b":"1F6B3","j":["bicycle","bike","forbidden","no","prohibited","cyclist","circle"]},"no-smoking":{"a":"No Smoking","b":"1F6AD","j":["forbidden","no","not","prohibited","smoking","cigarette","blue-square","smell","smoke"]},"no-littering":{"a":"No Littering","b":"1F6AF","j":["forbidden","litter","no","not","prohibited","trash","bin","garbage","circle"]},"nonpotable-water":{"a":"Non-Potable Water","b":"1F6B1","j":["non-drinking","non-potable","water","non_potable_water","drink","faucet","tap","circle"]},"no-pedestrians":{"a":"No Pedestrians","b":"1F6B7","j":["forbidden","no","not","pedestrian","prohibited","rules","crossing","walking","circle"]},"no-mobile-phones":{"a":"No Mobile Phones","b":"1F4F5","j":["cell","forbidden","mobile","no","phone","iphone","mute","circle"]},"no-one-under-eighteen":{"a":"No One Under Eighteen","b":"1F51E","j":["18","age restriction","eighteen","prohibited","underage","drink","pub","night","minor","circle"]},"radioactive":{"a":"Radioactive","b":"2622","j":["sign","nuclear","danger"]},"biohazard":{"a":"Biohazard","b":"2623","j":["sign","danger"]},"up-arrow":{"a":"Up Arrow","b":"2B06","j":["arrow","cardinal","direction","north","blue-square","continue","top"]},"upright-arrow":{"a":"Up-Right Arrow","b":"2197","j":["arrow","direction","intercardinal","northeast","up-right arrow","up_right_arrow","blue-square","point","diagonal"]},"right-arrow":{"a":"Right Arrow","b":"27A1","j":["arrow","cardinal","direction","east","blue-square","next"]},"downright-arrow":{"a":"Down-Right Arrow","b":"2198","j":["arrow","direction","down-right arrow","intercardinal","southeast","down_right_arrow","blue-square","diagonal"]},"down-arrow":{"a":"Down Arrow","b":"2B07","j":["arrow","cardinal","direction","down","south","blue-square","bottom"]},"downleft-arrow":{"a":"Down-Left Arrow","b":"2199","j":["arrow","direction","down-left arrow","intercardinal","southwest","down_left_arrow","blue-square","diagonal"]},"left-arrow":{"a":"Left Arrow","b":"2B05","j":["arrow","cardinal","direction","west","blue-square","previous","back"]},"upleft-arrow":{"a":"Up-Left Arrow","b":"2196","j":["arrow","direction","intercardinal","northwest","up-left arrow","up_left_arrow","blue-square","point","diagonal"]},"updown-arrow":{"a":"Up-Down Arrow","b":"2195","j":["arrow","up-down arrow","up_down_arrow","blue-square","direction","way","vertical"]},"leftright-arrow":{"a":"Left-Right Arrow","b":"2194","j":["arrow","left-right arrow","left_right_arrow","shape","direction","horizontal","sideways"]},"right-arrow-curving-left":{"a":"Right Arrow Curving Left","b":"21A9","j":["arrow","back","return","blue-square","undo","enter"]},"left-arrow-curving-right":{"a":"Left Arrow Curving Right","b":"21AA","j":["arrow","blue-square","return","rotate","direction"]},"right-arrow-curving-up":{"a":"Right Arrow Curving Up","b":"2934","j":["arrow","blue-square","direction","top"]},"right-arrow-curving-down":{"a":"Right Arrow Curving Down","b":"2935","j":["arrow","down","blue-square","direction","bottom"]},"clockwise-vertical-arrows":{"a":"Clockwise Vertical Arrows","b":"1F503","j":["arrow","clockwise","reload","sync","cycle","round","repeat"]},"counterclockwise-arrows-button":{"a":"Counterclockwise Arrows Button","b":"1F504","j":["anticlockwise","arrow","counterclockwise","withershins","blue-square","sync","cycle"]},"back-arrow":{"a":"Back Arrow","b":"1F519","j":["arrow","back","BACK arrow","words","return"]},"end-arrow":{"a":"End Arrow","b":"1F51A","j":["arrow","end","END arrow","words"]},"on-arrow":{"a":"On! Arrow","b":"1F51B","j":["arrow","mark","on","ON! arrow","words"]},"soon-arrow":{"a":"Soon Arrow","b":"1F51C","j":["arrow","soon","SOON arrow","words"]},"top-arrow":{"a":"Top Arrow","b":"1F51D","j":["arrow","top","TOP arrow","up","words","blue-square"]},"place-of-worship":{"a":"Place of Worship","b":"1F6D0","j":["religion","worship","church","temple","prayer"]},"atom-symbol":{"a":"Atom Symbol","b":"269B","j":["atheist","atom","science","physics","chemistry"]},"om":{"a":"Om","b":"1F549","j":["Hindu","religion","hinduism","buddhism","sikhism","jainism"]},"star-of-david":{"a":"Star of David","b":"2721","j":["David","Jew","Jewish","religion","star","star of David","judaism"]},"wheel-of-dharma":{"a":"Wheel of Dharma","b":"2638","j":["Buddhist","dharma","religion","wheel","hinduism","buddhism","sikhism","jainism"]},"yin-yang":{"a":"Yin Yang","b":"262F","j":["religion","tao","taoist","yang","yin","balance"]},"latin-cross":{"a":"Latin Cross","b":"271D","j":["Christian","cross","religion","christianity"]},"orthodox-cross":{"a":"Orthodox Cross","b":"2626","j":["Christian","cross","religion","suppedaneum"]},"star-and-crescent":{"a":"Star and Crescent","b":"262A","j":["islam","Muslim","religion"]},"peace-symbol":{"a":"Peace Symbol","b":"262E","j":["peace","hippie"]},"menorah":{"a":"Menorah","b":"1F54E","j":["candelabrum","candlestick","religion","hanukkah","candles","jewish"]},"dotted-sixpointed-star":{"a":"Dotted Six-Pointed Star","b":"1F52F","j":["dotted six-pointed star","fortune","star","dotted_six_pointed_star","purple-square","religion","jewish","hexagram"]},"aries":{"a":"Aries","b":"2648","j":["ram","zodiac","sign","purple-square","astrology"]},"taurus":{"a":"Taurus","b":"2649","j":["bull","ox","zodiac","purple-square","sign","astrology"]},"gemini":{"a":"Gemini","b":"264A","j":["twins","zodiac","sign","purple-square","astrology"]},"cancer":{"a":"Cancer","b":"264B","j":["crab","zodiac","sign","purple-square","astrology"]},"leo":{"a":"Leo","b":"264C","j":["lion","zodiac","sign","purple-square","astrology"]},"virgo":{"a":"Virgo","b":"264D","j":["zodiac","sign","purple-square","astrology"]},"libra":{"a":"Libra","b":"264E","j":["balance","justice","scales","zodiac","sign","purple-square","astrology"]},"scorpio":{"a":"Scorpio","b":"264F","j":["scorpion","scorpius","zodiac","sign","purple-square","astrology"]},"sagittarius":{"a":"Sagittarius","b":"2650","j":["archer","zodiac","sign","purple-square","astrology"]},"capricorn":{"a":"Capricorn","b":"2651","j":["goat","zodiac","sign","purple-square","astrology"]},"aquarius":{"a":"Aquarius","b":"2652","j":["bearer","water","zodiac","sign","purple-square","astrology"]},"pisces":{"a":"Pisces","b":"2653","j":["fish","zodiac","purple-square","sign","astrology"]},"ophiuchus":{"a":"Ophiuchus","b":"26CE","j":["bearer","serpent","snake","zodiac","sign","purple-square","constellation","astrology"]},"shuffle-tracks-button":{"a":"Shuffle Tracks Button","b":"1F500","j":["arrow","crossed","blue-square","shuffle","music","random"]},"repeat-button":{"a":"Repeat Button","b":"1F501","j":["arrow","clockwise","repeat","loop","record"]},"repeat-single-button":{"a":"Repeat Single Button","b":"1F502","j":["arrow","clockwise","once","blue-square","loop"]},"play-button":{"a":"Play Button","b":"25B6","j":["arrow","play","right","triangle","blue-square","direction"]},"fastforward-button":{"a":"Fast-Forward Button","b":"23E9","j":["arrow","double","fast","fast-forward button","forward","fast_forward_button","blue-square","play","speed","continue"]},"next-track-button":{"a":"Next Track Button","b":"23ED","j":["arrow","next scene","next track","triangle","forward","next","blue-square"]},"play-or-pause-button":{"a":"Play or Pause Button","b":"23EF","j":["arrow","pause","play","right","triangle","blue-square"]},"reverse-button":{"a":"Reverse Button","b":"25C0","j":["arrow","left","reverse","triangle","blue-square","direction"]},"fast-reverse-button":{"a":"Fast Reverse Button","b":"23EA","j":["arrow","double","rewind","play","blue-square"]},"last-track-button":{"a":"Last Track Button","b":"23EE","j":["arrow","previous scene","previous track","triangle","backward"]},"upwards-button":{"a":"Upwards Button","b":"1F53C","j":["arrow","button","red","blue-square","triangle","direction","point","forward","top"]},"fast-up-button":{"a":"Fast Up Button","b":"23EB","j":["arrow","double","blue-square","direction","top"]},"downwards-button":{"a":"Downwards Button","b":"1F53D","j":["arrow","button","down","red","blue-square","direction","bottom"]},"fast-down-button":{"a":"Fast Down Button","b":"23EC","j":["arrow","double","down","blue-square","direction","bottom"]},"pause-button":{"a":"Pause Button","b":"23F8","j":["bar","double","pause","vertical","blue-square"]},"stop-button":{"a":"Stop Button","b":"23F9","j":["square","stop","blue-square"]},"record-button":{"a":"Record Button","b":"23FA","j":["circle","record","blue-square"]},"eject-button":{"a":"Eject Button","b":"23CF","j":["eject","blue-square"]},"cinema":{"a":"Cinema","b":"1F3A6","j":["camera","film","movie","blue-square","record","curtain","stage","theater"]},"dim-button":{"a":"Dim Button","b":"1F505","j":["brightness","dim","low","sun","afternoon","warm","summer"]},"bright-button":{"a":"Bright Button","b":"1F506","j":["bright","brightness","sun","light"]},"antenna-bars":{"a":"Antenna Bars","b":"1F4F6","j":["antenna","bar","cell","mobile","phone","blue-square","reception","internet","connection","wifi","bluetooth","bars"]},"vibration-mode":{"a":"Vibration Mode","b":"1F4F3","j":["cell","mobile","mode","phone","telephone","vibration","orange-square"]},"mobile-phone-off":{"a":"Mobile Phone off","b":"1F4F4","j":["cell","mobile","off","phone","telephone","mute","orange-square","silence","quiet"]},"female-sign":{"a":"Female Sign","b":"2640","j":["woman","women","lady","girl"]},"male-sign":{"a":"Male Sign","b":"2642","j":["man","boy","men"]},"transgender-symbol":{"a":"Transgender Symbol","b":"26A7","j":["transgender","lgbtq"]},"multiply":{"a":"Multiply","b":"2716","j":["×","cancel","multiplication","sign","x","multiplication_sign","math","calculation"]},"plus":{"a":"Plus","b":"2795","j":["+","math","sign","plus_sign","calculation","addition","more","increase"]},"minus":{"a":"Minus","b":"2796","j":["-","−","math","sign","minus_sign","calculation","subtract","less"]},"divide":{"a":"Divide","b":"2797","j":["÷","division","math","sign","division_sign","calculation"]},"heavy-equals-sign":{"a":"⊛ Heavy Equals Sign","b":"1F7F0","j":["equality","math"]},"infinity":{"a":"Infinity","b":"267E","j":["forever","unbounded","universal"]},"double-exclamation-mark":{"a":"Double Exclamation Mark","b":"203C","j":["!","!!","bangbang","exclamation","mark","surprise"]},"exclamation-question-mark":{"a":"Exclamation Question Mark","b":"2049","j":["!","!?","?","exclamation","interrobang","mark","punctuation","question","wat","surprise"]},"red-question-mark":{"a":"Red Question Mark","b":"2753","j":["?","mark","punctuation","question","question_mark","doubt","confused"]},"white-question-mark":{"a":"White Question Mark","b":"2754","j":["?","mark","outlined","punctuation","question","doubts","gray","huh","confused"]},"white-exclamation-mark":{"a":"White Exclamation Mark","b":"2755","j":["!","exclamation","mark","outlined","punctuation","surprise","gray","wow","warning"]},"red-exclamation-mark":{"a":"Red Exclamation Mark","b":"2757","j":["!","exclamation","mark","punctuation","exclamation_mark","heavy_exclamation_mark","danger","surprise","wow","warning"]},"wavy-dash":{"a":"Wavy Dash","b":"3030","j":["dash","punctuation","wavy","draw","line","moustache","mustache","squiggle","scribble"]},"currency-exchange":{"a":"Currency Exchange","b":"1F4B1","j":["bank","currency","exchange","money","sales","dollar","travel"]},"heavy-dollar-sign":{"a":"Heavy Dollar Sign","b":"1F4B2","j":["currency","dollar","money","sales","payment","buck"]},"medical-symbol":{"a":"Medical Symbol","b":"2695","j":["aesculapius","medicine","staff","health","hospital"]},"recycling-symbol":{"a":"Recycling Symbol","b":"267B","j":["recycle","arrow","environment","garbage","trash"]},"fleurdelis":{"a":"Fleur-De-Lis","b":"269C","j":["fleur-de-lis","fleur_de_lis","decorative","scout"]},"trident-emblem":{"a":"Trident Emblem","b":"1F531","j":["anchor","emblem","ship","tool","trident","weapon","spear"]},"name-badge":{"a":"Name Badge","b":"1F4DB","j":["badge","name","fire","forbid"]},"japanese-symbol-for-beginner":{"a":"Japanese Symbol for Beginner","b":"1F530","j":["beginner","chevron","Japanese","Japanese symbol for beginner","leaf","badge","shield"]},"hollow-red-circle":{"a":"Hollow Red Circle","b":"2B55","j":["circle","large","o","red","round"]},"check-mark-button":{"a":"Check Mark Button","b":"2705","j":["✓","button","check","mark","green-square","ok","agree","vote","election","answer","tick"]},"check-box-with-check":{"a":"Check Box with Check","b":"2611","j":["✓","box","check","ok","agree","confirm","black-square","vote","election","yes","tick"]},"check-mark":{"a":"Check Mark","b":"2714","j":["✓","check","mark","ok","nike","answer","yes","tick"]},"cross-mark":{"a":"Cross Mark","b":"274C","j":["×","cancel","cross","mark","multiplication","multiply","x","no","delete","remove","red"]},"cross-mark-button":{"a":"Cross Mark Button","b":"274E","j":["×","mark","square","x","green-square","no","deny"]},"curly-loop":{"a":"Curly Loop","b":"27B0","j":["curl","loop","scribble","draw","shape","squiggle"]},"double-curly-loop":{"a":"Double Curly Loop","b":"27BF","j":["curl","double","loop","tape","cassette"]},"part-alternation-mark":{"a":"Part Alternation Mark","b":"303D","j":["mark","part","graph","presentation","stats","business","economics","bad"]},"eightspoked-asterisk":{"a":"Eight-Spoked Asterisk","b":"2733","j":["*","asterisk","eight-spoked asterisk","eight_spoked_asterisk","star","sparkle","green-square"]},"eightpointed-star":{"a":"Eight-Pointed Star","b":"2734","j":["*","eight-pointed star","star","eight_pointed_star","orange-square","shape","polygon"]},"sparkle":{"a":"Sparkle","b":"2747","j":["*","stars","green-square","awesome","good","fireworks"]},"copyright":{"a":"Copyright","b":"00A9","j":["c","ip","license","circle","law","legal"]},"registered":{"a":"Registered","b":"00AE","j":["r","alphabet","circle"]},"trade-mark":{"a":"Trade Mark","b":"2122","j":["mark","tm","trademark","brand","law","legal"]},"keycap":{"a":"Keycap: *","b":"002A-FE0F-20E3","j":["keycap_","star"]},"keycap-0":{"a":"Keycap: 0","b":"0030-FE0F-20E3","j":["keycap","0","numbers","blue-square","null"]},"keycap-1":{"a":"Keycap: 1","b":"0031-FE0F-20E3","j":["keycap","blue-square","numbers","1"]},"keycap-2":{"a":"Keycap: 2","b":"0032-FE0F-20E3","j":["keycap","numbers","2","prime","blue-square"]},"keycap-3":{"a":"Keycap: 3","b":"0033-FE0F-20E3","j":["keycap","3","numbers","prime","blue-square"]},"keycap-4":{"a":"Keycap: 4","b":"0034-FE0F-20E3","j":["keycap","4","numbers","blue-square"]},"keycap-5":{"a":"Keycap: 5","b":"0035-FE0F-20E3","j":["keycap","5","numbers","blue-square","prime"]},"keycap-6":{"a":"Keycap: 6","b":"0036-FE0F-20E3","j":["keycap","6","numbers","blue-square"]},"keycap-7":{"a":"Keycap: 7","b":"0037-FE0F-20E3","j":["keycap","7","numbers","blue-square","prime"]},"keycap-8":{"a":"Keycap: 8","b":"0038-FE0F-20E3","j":["keycap","8","blue-square","numbers"]},"keycap-9":{"a":"Keycap: 9","b":"0039-FE0F-20E3","j":["keycap","blue-square","numbers","9"]},"keycap-10":{"a":"Keycap: 10","b":"1F51F","j":["keycap","numbers","10","blue-square"]},"input-latin-uppercase":{"a":"Input Latin Uppercase","b":"1F520","j":["ABCD","input","latin","letters","uppercase","alphabet","words","blue-square"]},"input-latin-lowercase":{"a":"Input Latin Lowercase","b":"1F521","j":["abcd","input","latin","letters","lowercase","blue-square","alphabet"]},"input-numbers":{"a":"Input Numbers","b":"1F522","j":["1234","input","numbers","blue-square"]},"input-symbols":{"a":"Input Symbols","b":"1F523","j":["〒♪&%","input","blue-square","music","note","ampersand","percent","glyphs","characters"]},"input-latin-letters":{"a":"Input Latin Letters","b":"1F524","j":["abc","alphabet","input","latin","letters","blue-square"]},"a-button-blood-type":{"a":"A Button (Blood Type)","b":"1F170","j":["a","A button (blood type)","blood type","a_button","red-square","alphabet","letter"]},"ab-button-blood-type":{"a":"Ab Button (Blood Type)","b":"1F18E","j":["ab","AB button (blood type)","blood type","ab_button","red-square","alphabet"]},"b-button-blood-type":{"a":"B Button (Blood Type)","b":"1F171","j":["b","B button (blood type)","blood type","b_button","red-square","alphabet","letter"]},"cl-button":{"a":"Cl Button","b":"1F191","j":["cl","CL button","alphabet","words","red-square"]},"cool-button":{"a":"Cool Button","b":"1F192","j":["cool","COOL button","words","blue-square"]},"free-button":{"a":"Free Button","b":"1F193","j":["free","FREE button","blue-square","words"]},"information":{"a":"Information","b":"2139","j":["i","blue-square","alphabet","letter"]},"id-button":{"a":"Id Button","b":"1F194","j":["id","ID button","identity","purple-square","words"]},"circled-m":{"a":"Circled M","b":"24C2","j":["circle","circled M","m","alphabet","blue-circle","letter"]},"new-button":{"a":"New Button","b":"1F195","j":["new","NEW button","blue-square","words","start"]},"ng-button":{"a":"Ng Button","b":"1F196","j":["ng","NG button","blue-square","words","shape","icon"]},"o-button-blood-type":{"a":"O Button (Blood Type)","b":"1F17E","j":["blood type","o","O button (blood type)","o_button","alphabet","red-square","letter"]},"ok-button":{"a":"Ok Button","b":"1F197","j":["OK","OK button","good","agree","yes","blue-square"]},"p-button":{"a":"P Button","b":"1F17F","j":["P button","parking","cars","blue-square","alphabet","letter"]},"sos-button":{"a":"Sos Button","b":"1F198","j":["help","sos","SOS button","red-square","words","emergency","911"]},"up-button":{"a":"Up! Button","b":"1F199","j":["mark","up","UP! button","blue-square","above","high"]},"vs-button":{"a":"Vs Button","b":"1F19A","j":["versus","vs","VS button","words","orange-square"]},"japanese-here-button":{"a":"Japanese “Here” Button","b":"1F201","j":["“here”","Japanese","Japanese “here” button","katakana","ココ","blue-square","here","japanese","destination"]},"japanese-service-charge-button":{"a":"Japanese “Service Charge” Button","b":"1F202","j":["“service charge”","Japanese","Japanese “service charge” button","katakana","サ","japanese","blue-square"]},"japanese-monthly-amount-button":{"a":"Japanese “Monthly Amount” Button","b":"1F237","j":["“monthly amount”","ideograph","Japanese","Japanese “monthly amount” button","月","chinese","month","moon","japanese","orange-square","kanji"]},"japanese-not-free-of-charge-button":{"a":"Japanese “Not Free of Charge” Button","b":"1F236","j":["“not free of charge”","ideograph","Japanese","Japanese “not free of charge” button","有","orange-square","chinese","have","kanji"]},"japanese-reserved-button":{"a":"Japanese “Reserved” Button","b":"1F22F","j":["“reserved”","ideograph","Japanese","Japanese “reserved” button","指","chinese","point","green-square","kanji"]},"japanese-bargain-button":{"a":"Japanese “Bargain” Button","b":"1F250","j":["“bargain”","ideograph","Japanese","Japanese “bargain” button","得","chinese","kanji","obtain","get","circle"]},"japanese-discount-button":{"a":"Japanese “Discount” Button","b":"1F239","j":["“discount”","ideograph","Japanese","Japanese “discount” button","割","cut","divide","chinese","kanji","pink-square"]},"japanese-free-of-charge-button":{"a":"Japanese “Free of Charge” Button","b":"1F21A","j":["“free of charge”","ideograph","Japanese","Japanese “free of charge” button","無","nothing","chinese","kanji","japanese","orange-square"]},"japanese-prohibited-button":{"a":"Japanese “Prohibited” Button","b":"1F232","j":["“prohibited”","ideograph","Japanese","Japanese “prohibited” button","禁","kanji","japanese","chinese","forbidden","limit","restricted","red-square"]},"japanese-acceptable-button":{"a":"Japanese “Acceptable” Button","b":"1F251","j":["“acceptable”","ideograph","Japanese","Japanese “acceptable” button","可","ok","good","chinese","kanji","agree","yes","orange-circle"]},"japanese-application-button":{"a":"Japanese “Application” Button","b":"1F238","j":["“application”","ideograph","Japanese","Japanese “application” button","申","chinese","japanese","kanji","orange-square"]},"japanese-passing-grade-button":{"a":"Japanese “Passing Grade” Button","b":"1F234","j":["“passing grade”","ideograph","Japanese","Japanese “passing grade” button","合","japanese","chinese","join","kanji","red-square"]},"japanese-vacancy-button":{"a":"Japanese “Vacancy” Button","b":"1F233","j":["“vacancy”","ideograph","Japanese","Japanese “vacancy” button","空","kanji","japanese","chinese","empty","sky","blue-square"]},"japanese-congratulations-button":{"a":"Japanese “Congratulations” Button","b":"3297","j":["“congratulations”","ideograph","Japanese","Japanese “congratulations” button","祝","chinese","kanji","japanese","red-circle"]},"japanese-secret-button":{"a":"Japanese “Secret” Button","b":"3299","j":["“secret”","ideograph","Japanese","Japanese “secret” button","秘","privacy","chinese","sshh","kanji","red-circle"]},"japanese-open-for-business-button":{"a":"Japanese “Open for Business” Button","b":"1F23A","j":["“open for business”","ideograph","Japanese","Japanese “open for business” button","営","japanese","opening hours","orange-square"]},"japanese-no-vacancy-button":{"a":"Japanese “No Vacancy” Button","b":"1F235","j":["“no vacancy”","ideograph","Japanese","Japanese “no vacancy” button","満","full","chinese","japanese","red-square","kanji"]},"red-circle":{"a":"Red Circle","b":"1F534","j":["circle","geometric","red","shape","error","danger"]},"orange-circle":{"a":"Orange Circle","b":"1F7E0","j":["circle","orange","round"]},"yellow-circle":{"a":"Yellow Circle","b":"1F7E1","j":["circle","yellow","round"]},"green-circle":{"a":"Green Circle","b":"1F7E2","j":["circle","green","round"]},"blue-circle":{"a":"Blue Circle","b":"1F535","j":["blue","circle","geometric","shape","icon","button"]},"purple-circle":{"a":"Purple Circle","b":"1F7E3","j":["circle","purple","round"]},"brown-circle":{"a":"Brown Circle","b":"1F7E4","j":["brown","circle","round"]},"black-circle":{"a":"Black Circle","b":"26AB","j":["circle","geometric","shape","button","round"]},"white-circle":{"a":"White Circle","b":"26AA","j":["circle","geometric","shape","round"]},"red-square":{"a":"Red Square","b":"1F7E5","j":["red","square"]},"orange-square":{"a":"Orange Square","b":"1F7E7","j":["orange","square"]},"yellow-square":{"a":"Yellow Square","b":"1F7E8","j":["square","yellow"]},"green-square":{"a":"Green Square","b":"1F7E9","j":["green","square"]},"blue-square":{"a":"Blue Square","b":"1F7E6","j":["blue","square"]},"purple-square":{"a":"Purple Square","b":"1F7EA","j":["purple","square"]},"brown-square":{"a":"Brown Square","b":"1F7EB","j":["brown","square"]},"black-large-square":{"a":"Black Large Square","b":"2B1B","j":["geometric","square","shape","icon","button"]},"white-large-square":{"a":"White Large Square","b":"2B1C","j":["geometric","square","shape","icon","stone","button"]},"black-medium-square":{"a":"Black Medium Square","b":"25FC","j":["geometric","square","shape","button","icon"]},"white-medium-square":{"a":"White Medium Square","b":"25FB","j":["geometric","square","shape","stone","icon"]},"black-mediumsmall-square":{"a":"Black Medium-Small Square","b":"25FE","j":["black medium-small square","geometric","square","black_medium_small_square","icon","shape","button"]},"white-mediumsmall-square":{"a":"White Medium-Small Square","b":"25FD","j":["geometric","square","white medium-small square","white_medium_small_square","shape","stone","icon","button"]},"black-small-square":{"a":"Black Small Square","b":"25AA","j":["geometric","square","shape","icon"]},"white-small-square":{"a":"White Small Square","b":"25AB","j":["geometric","square","shape","icon"]},"large-orange-diamond":{"a":"Large Orange Diamond","b":"1F536","j":["diamond","geometric","orange","shape","jewel","gem"]},"large-blue-diamond":{"a":"Large Blue Diamond","b":"1F537","j":["blue","diamond","geometric","shape","jewel","gem"]},"small-orange-diamond":{"a":"Small Orange Diamond","b":"1F538","j":["diamond","geometric","orange","shape","jewel","gem"]},"small-blue-diamond":{"a":"Small Blue Diamond","b":"1F539","j":["blue","diamond","geometric","shape","jewel","gem"]},"red-triangle-pointed-up":{"a":"Red Triangle Pointed Up","b":"1F53A","j":["geometric","red","shape","direction","up","top"]},"red-triangle-pointed-down":{"a":"Red Triangle Pointed Down","b":"1F53B","j":["down","geometric","red","shape","direction","bottom"]},"diamond-with-a-dot":{"a":"Diamond with a Dot","b":"1F4A0","j":["comic","diamond","geometric","inside","jewel","blue","gem","crystal","fancy"]},"radio-button":{"a":"Radio Button","b":"1F518","j":["button","geometric","radio","input","old","music","circle"]},"white-square-button":{"a":"White Square Button","b":"1F533","j":["button","geometric","outlined","square","shape","input"]},"black-square-button":{"a":"Black Square Button","b":"1F532","j":["button","geometric","square","shape","input","frame"]},"chequered-flag":{"a":"Chequered Flag","b":"1F3C1","j":["checkered","chequered","racing","contest","finishline","race","gokart"]},"triangular-flag":{"a":"Triangular Flag","b":"1F6A9","j":["post","mark","milestone","place"]},"crossed-flags":{"a":"Crossed Flags","b":"1F38C","j":["celebration","cross","crossed","Japanese","japanese","nation","country","border"]},"black-flag":{"a":"Black Flag","b":"1F3F4","j":["waving","pirate"]},"white-flag":{"a":"White Flag","b":"1F3F3","j":["waving","losing","loser","lost","surrender","give up","fail"]},"rainbow-flag":{"a":"Rainbow Flag","b":"1F3F3-FE0F-200D-1F308","j":["pride","rainbow","flag","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"]},"transgender-flag":{"a":"Transgender Flag","b":"1F3F3-FE0F-200D-26A7-FE0F","j":["flag","light blue","pink","transgender","white","lgbtq"]},"pirate-flag":{"a":"Pirate Flag","b":"1F3F4-200D-2620-FE0F","j":["Jolly Roger","pirate","plunder","treasure","skull","crossbones","flag","banner"]},"flag-ascension-island":{"a":"Flag: Ascension Island","b":"1F1E6-1F1E8","j":["flag"]},"flag-andorra":{"a":"Flag: Andorra","b":"1F1E6-1F1E9","j":["flag","ad","nation","country","banner","andorra"]},"flag-united-arab-emirates":{"a":"Flag: United Arab Emirates","b":"1F1E6-1F1EA","j":["flag","united","arab","emirates","nation","country","banner","united_arab_emirates"]},"flag-afghanistan":{"a":"Flag: Afghanistan","b":"1F1E6-1F1EB","j":["flag","af","nation","country","banner","afghanistan"]},"flag-antigua--barbuda":{"a":"Flag: Antigua & Barbuda","b":"1F1E6-1F1EC","j":["flag","flag_antigua_barbuda","antigua","barbuda","nation","country","banner","antigua_barbuda"]},"flag-anguilla":{"a":"Flag: Anguilla","b":"1F1E6-1F1EE","j":["flag","ai","nation","country","banner","anguilla"]},"flag-albania":{"a":"Flag: Albania","b":"1F1E6-1F1F1","j":["flag","al","nation","country","banner","albania"]},"flag-armenia":{"a":"Flag: Armenia","b":"1F1E6-1F1F2","j":["flag","am","nation","country","banner","armenia"]},"flag-angola":{"a":"Flag: Angola","b":"1F1E6-1F1F4","j":["flag","ao","nation","country","banner","angola"]},"flag-antarctica":{"a":"Flag: Antarctica","b":"1F1E6-1F1F6","j":["flag","aq","nation","country","banner","antarctica"]},"flag-argentina":{"a":"Flag: Argentina","b":"1F1E6-1F1F7","j":["flag","ar","nation","country","banner","argentina"]},"flag-american-samoa":{"a":"Flag: American Samoa","b":"1F1E6-1F1F8","j":["flag","american","ws","nation","country","banner","american_samoa"]},"flag-austria":{"a":"Flag: Austria","b":"1F1E6-1F1F9","j":["flag","at","nation","country","banner","austria"]},"flag-australia":{"a":"Flag: Australia","b":"1F1E6-1F1FA","j":["flag","au","nation","country","banner","australia"]},"flag-aruba":{"a":"Flag: Aruba","b":"1F1E6-1F1FC","j":["flag","aw","nation","country","banner","aruba"]},"flag-land-islands":{"a":"Flag: Åland Islands","b":"1F1E6-1F1FD","j":["flag","flag_aland_islands","Åland","islands","nation","country","banner","aland_islands"]},"flag-azerbaijan":{"a":"Flag: Azerbaijan","b":"1F1E6-1F1FF","j":["flag","az","nation","country","banner","azerbaijan"]},"flag-bosnia--herzegovina":{"a":"Flag: Bosnia & Herzegovina","b":"1F1E7-1F1E6","j":["flag","flag_bosnia_herzegovina","bosnia","herzegovina","nation","country","banner","bosnia_herzegovina"]},"flag-barbados":{"a":"Flag: Barbados","b":"1F1E7-1F1E7","j":["flag","bb","nation","country","banner","barbados"]},"flag-bangladesh":{"a":"Flag: Bangladesh","b":"1F1E7-1F1E9","j":["flag","bd","nation","country","banner","bangladesh"]},"flag-belgium":{"a":"Flag: Belgium","b":"1F1E7-1F1EA","j":["flag","be","nation","country","banner","belgium"]},"flag-burkina-faso":{"a":"Flag: Burkina Faso","b":"1F1E7-1F1EB","j":["flag","burkina","faso","nation","country","banner","burkina_faso"]},"flag-bulgaria":{"a":"Flag: Bulgaria","b":"1F1E7-1F1EC","j":["flag","bg","nation","country","banner","bulgaria"]},"flag-bahrain":{"a":"Flag: Bahrain","b":"1F1E7-1F1ED","j":["flag","bh","nation","country","banner","bahrain"]},"flag-burundi":{"a":"Flag: Burundi","b":"1F1E7-1F1EE","j":["flag","bi","nation","country","banner","burundi"]},"flag-benin":{"a":"Flag: Benin","b":"1F1E7-1F1EF","j":["flag","bj","nation","country","banner","benin"]},"flag-st-barthlemy":{"a":"Flag: St. Barthélemy","b":"1F1E7-1F1F1","j":["flag","flag_st_barthelemy","saint","barthélemy","nation","country","banner","st_barthelemy"]},"flag-bermuda":{"a":"Flag: Bermuda","b":"1F1E7-1F1F2","j":["flag","bm","nation","country","banner","bermuda"]},"flag-brunei":{"a":"Flag: Brunei","b":"1F1E7-1F1F3","j":["flag","bn","darussalam","nation","country","banner","brunei"]},"flag-bolivia":{"a":"Flag: Bolivia","b":"1F1E7-1F1F4","j":["flag","bo","nation","country","banner","bolivia"]},"flag-caribbean-netherlands":{"a":"Flag: Caribbean Netherlands","b":"1F1E7-1F1F6","j":["flag","bonaire","nation","country","banner","caribbean_netherlands"]},"flag-brazil":{"a":"Flag: Brazil","b":"1F1E7-1F1F7","j":["flag","br","nation","country","banner","brazil"]},"flag-bahamas":{"a":"Flag: Bahamas","b":"1F1E7-1F1F8","j":["flag","bs","nation","country","banner","bahamas"]},"flag-bhutan":{"a":"Flag: Bhutan","b":"1F1E7-1F1F9","j":["flag","bt","nation","country","banner","bhutan"]},"flag-bouvet-island":{"a":"Flag: Bouvet Island","b":"1F1E7-1F1FB","j":["flag","norway"]},"flag-botswana":{"a":"Flag: Botswana","b":"1F1E7-1F1FC","j":["flag","bw","nation","country","banner","botswana"]},"flag-belarus":{"a":"Flag: Belarus","b":"1F1E7-1F1FE","j":["flag","by","nation","country","banner","belarus"]},"flag-belize":{"a":"Flag: Belize","b":"1F1E7-1F1FF","j":["flag","bz","nation","country","banner","belize"]},"flag-canada":{"a":"Flag: Canada","b":"1F1E8-1F1E6","j":["flag","ca","nation","country","banner","canada"]},"flag-cocos-keeling-islands":{"a":"Flag: Cocos (Keeling) Islands","b":"1F1E8-1F1E8","j":["flag","flag_cocos_islands","cocos","keeling","islands","nation","country","banner","cocos_islands"]},"flag-congo--kinshasa":{"a":"Flag: Congo - Kinshasa","b":"1F1E8-1F1E9","j":["flag","flag_congo_kinshasa","congo","democratic","republic","nation","country","banner","congo_kinshasa"]},"flag-central-african-republic":{"a":"Flag: Central African Republic","b":"1F1E8-1F1EB","j":["flag","central","african","republic","nation","country","banner","central_african_republic"]},"flag-congo--brazzaville":{"a":"Flag: Congo - Brazzaville","b":"1F1E8-1F1EC","j":["flag","flag_congo_brazzaville","congo","nation","country","banner","congo_brazzaville"]},"flag-switzerland":{"a":"Flag: Switzerland","b":"1F1E8-1F1ED","j":["flag","ch","nation","country","banner","switzerland"]},"flag-cte-divoire":{"a":"Flag: Côte D’Ivoire","b":"1F1E8-1F1EE","j":["flag","flag_cote_d_ivoire","ivory","coast","nation","country","banner","cote_d_ivoire"]},"flag-cook-islands":{"a":"Flag: Cook Islands","b":"1F1E8-1F1F0","j":["flag","cook","islands","nation","country","banner","cook_islands"]},"flag-chile":{"a":"Flag: Chile","b":"1F1E8-1F1F1","j":["flag","nation","country","banner","chile"]},"flag-cameroon":{"a":"Flag: Cameroon","b":"1F1E8-1F1F2","j":["flag","cm","nation","country","banner","cameroon"]},"flag-china":{"a":"Flag: China","b":"1F1E8-1F1F3","j":["flag","china","chinese","prc","country","nation","banner"]},"flag-colombia":{"a":"Flag: Colombia","b":"1F1E8-1F1F4","j":["flag","co","nation","country","banner","colombia"]},"flag-clipperton-island":{"a":"Flag: Clipperton Island","b":"1F1E8-1F1F5","j":["flag"]},"flag-costa-rica":{"a":"Flag: Costa Rica","b":"1F1E8-1F1F7","j":["flag","costa","rica","nation","country","banner","costa_rica"]},"flag-cuba":{"a":"Flag: Cuba","b":"1F1E8-1F1FA","j":["flag","cu","nation","country","banner","cuba"]},"flag-cape-verde":{"a":"Flag: Cape Verde","b":"1F1E8-1F1FB","j":["flag","cabo","verde","nation","country","banner","cape_verde"]},"flag-curaao":{"a":"Flag: Curaçao","b":"1F1E8-1F1FC","j":["flag","flag_curacao","curaçao","nation","country","banner","curacao"]},"flag-christmas-island":{"a":"Flag: Christmas Island","b":"1F1E8-1F1FD","j":["flag","christmas","island","nation","country","banner","christmas_island"]},"flag-cyprus":{"a":"Flag: Cyprus","b":"1F1E8-1F1FE","j":["flag","cy","nation","country","banner","cyprus"]},"flag-czechia":{"a":"Flag: Czechia","b":"1F1E8-1F1FF","j":["flag","cz","nation","country","banner","czechia"]},"flag-germany":{"a":"Flag: Germany","b":"1F1E9-1F1EA","j":["flag","german","nation","country","banner","germany"]},"flag-diego-garcia":{"a":"Flag: Diego Garcia","b":"1F1E9-1F1EC","j":["flag"]},"flag-djibouti":{"a":"Flag: Djibouti","b":"1F1E9-1F1EF","j":["flag","dj","nation","country","banner","djibouti"]},"flag-denmark":{"a":"Flag: Denmark","b":"1F1E9-1F1F0","j":["flag","dk","nation","country","banner","denmark"]},"flag-dominica":{"a":"Flag: Dominica","b":"1F1E9-1F1F2","j":["flag","dm","nation","country","banner","dominica"]},"flag-dominican-republic":{"a":"Flag: Dominican Republic","b":"1F1E9-1F1F4","j":["flag","dominican","republic","nation","country","banner","dominican_republic"]},"flag-algeria":{"a":"Flag: Algeria","b":"1F1E9-1F1FF","j":["flag","dz","nation","country","banner","algeria"]},"flag-ceuta--melilla":{"a":"Flag: Ceuta & Melilla","b":"1F1EA-1F1E6","j":["flag","flag_ceuta_melilla"]},"flag-ecuador":{"a":"Flag: Ecuador","b":"1F1EA-1F1E8","j":["flag","ec","nation","country","banner","ecuador"]},"flag-estonia":{"a":"Flag: Estonia","b":"1F1EA-1F1EA","j":["flag","ee","nation","country","banner","estonia"]},"flag-egypt":{"a":"Flag: Egypt","b":"1F1EA-1F1EC","j":["flag","eg","nation","country","banner","egypt"]},"flag-western-sahara":{"a":"Flag: Western Sahara","b":"1F1EA-1F1ED","j":["flag","western","sahara","nation","country","banner","western_sahara"]},"flag-eritrea":{"a":"Flag: Eritrea","b":"1F1EA-1F1F7","j":["flag","er","nation","country","banner","eritrea"]},"flag-spain":{"a":"Flag: Spain","b":"1F1EA-1F1F8","j":["flag","spain","nation","country","banner"]},"flag-ethiopia":{"a":"Flag: Ethiopia","b":"1F1EA-1F1F9","j":["flag","et","nation","country","banner","ethiopia"]},"flag-european-union":{"a":"Flag: European Union","b":"1F1EA-1F1FA","j":["flag","european","union","banner"]},"flag-finland":{"a":"Flag: Finland","b":"1F1EB-1F1EE","j":["flag","fi","nation","country","banner","finland"]},"flag-fiji":{"a":"Flag: Fiji","b":"1F1EB-1F1EF","j":["flag","fj","nation","country","banner","fiji"]},"flag-falkland-islands":{"a":"Flag: Falkland Islands","b":"1F1EB-1F1F0","j":["flag","falkland","islands","malvinas","nation","country","banner","falkland_islands"]},"flag-micronesia":{"a":"Flag: Micronesia","b":"1F1EB-1F1F2","j":["flag","micronesia","federated","states","nation","country","banner"]},"flag-faroe-islands":{"a":"Flag: Faroe Islands","b":"1F1EB-1F1F4","j":["flag","faroe","islands","nation","country","banner","faroe_islands"]},"flag-france":{"a":"Flag: France","b":"1F1EB-1F1F7","j":["flag","banner","nation","france","french","country"]},"flag-gabon":{"a":"Flag: Gabon","b":"1F1EC-1F1E6","j":["flag","ga","nation","country","banner","gabon"]},"flag-united-kingdom":{"a":"Flag: United Kingdom","b":"1F1EC-1F1E7","j":["flag","united","kingdom","great","britain","northern","ireland","nation","country","banner","british","UK","english","england","union jack","united_kingdom"]},"flag-grenada":{"a":"Flag: Grenada","b":"1F1EC-1F1E9","j":["flag","gd","nation","country","banner","grenada"]},"flag-georgia":{"a":"Flag: Georgia","b":"1F1EC-1F1EA","j":["flag","ge","nation","country","banner","georgia"]},"flag-french-guiana":{"a":"Flag: French Guiana","b":"1F1EC-1F1EB","j":["flag","french","guiana","nation","country","banner","french_guiana"]},"flag-guernsey":{"a":"Flag: Guernsey","b":"1F1EC-1F1EC","j":["flag","gg","nation","country","banner","guernsey"]},"flag-ghana":{"a":"Flag: Ghana","b":"1F1EC-1F1ED","j":["flag","gh","nation","country","banner","ghana"]},"flag-gibraltar":{"a":"Flag: Gibraltar","b":"1F1EC-1F1EE","j":["flag","gi","nation","country","banner","gibraltar"]},"flag-greenland":{"a":"Flag: Greenland","b":"1F1EC-1F1F1","j":["flag","gl","nation","country","banner","greenland"]},"flag-gambia":{"a":"Flag: Gambia","b":"1F1EC-1F1F2","j":["flag","gm","nation","country","banner","gambia"]},"flag-guinea":{"a":"Flag: Guinea","b":"1F1EC-1F1F3","j":["flag","gn","nation","country","banner","guinea"]},"flag-guadeloupe":{"a":"Flag: Guadeloupe","b":"1F1EC-1F1F5","j":["flag","gp","nation","country","banner","guadeloupe"]},"flag-equatorial-guinea":{"a":"Flag: Equatorial Guinea","b":"1F1EC-1F1F6","j":["flag","equatorial","gn","nation","country","banner","equatorial_guinea"]},"flag-greece":{"a":"Flag: Greece","b":"1F1EC-1F1F7","j":["flag","gr","nation","country","banner","greece"]},"flag-south-georgia--south-sandwich-islands":{"a":"Flag: South Georgia & South Sandwich Islands","b":"1F1EC-1F1F8","j":["flag","flag_south_georgia_south_sandwich_islands","south","georgia","sandwich","islands","nation","country","banner","south_georgia_south_sandwich_islands"]},"flag-guatemala":{"a":"Flag: Guatemala","b":"1F1EC-1F1F9","j":["flag","gt","nation","country","banner","guatemala"]},"flag-guam":{"a":"Flag: Guam","b":"1F1EC-1F1FA","j":["flag","gu","nation","country","banner","guam"]},"flag-guineabissau":{"a":"Flag: Guinea-Bissau","b":"1F1EC-1F1FC","j":["flag","flag_guinea_bissau","gw","bissau","nation","country","banner","guinea_bissau"]},"flag-guyana":{"a":"Flag: Guyana","b":"1F1EC-1F1FE","j":["flag","gy","nation","country","banner","guyana"]},"flag-hong-kong-sar-china":{"a":"Flag: Hong Kong Sar China","b":"1F1ED-1F1F0","j":["flag","hong","kong","nation","country","banner","hong_kong_sar_china"]},"flag-heard--mcdonald-islands":{"a":"Flag: Heard & Mcdonald Islands","b":"1F1ED-1F1F2","j":["flag","flag_heard_mcdonald_islands"]},"flag-honduras":{"a":"Flag: Honduras","b":"1F1ED-1F1F3","j":["flag","hn","nation","country","banner","honduras"]},"flag-croatia":{"a":"Flag: Croatia","b":"1F1ED-1F1F7","j":["flag","hr","nation","country","banner","croatia"]},"flag-haiti":{"a":"Flag: Haiti","b":"1F1ED-1F1F9","j":["flag","ht","nation","country","banner","haiti"]},"flag-hungary":{"a":"Flag: Hungary","b":"1F1ED-1F1FA","j":["flag","hu","nation","country","banner","hungary"]},"flag-canary-islands":{"a":"Flag: Canary Islands","b":"1F1EE-1F1E8","j":["flag","canary","islands","nation","country","banner","canary_islands"]},"flag-indonesia":{"a":"Flag: Indonesia","b":"1F1EE-1F1E9","j":["flag","nation","country","banner","indonesia"]},"flag-ireland":{"a":"Flag: Ireland","b":"1F1EE-1F1EA","j":["flag","ie","nation","country","banner","ireland"]},"flag-israel":{"a":"Flag: Israel","b":"1F1EE-1F1F1","j":["flag","il","nation","country","banner","israel"]},"flag-isle-of-man":{"a":"Flag: Isle of Man","b":"1F1EE-1F1F2","j":["flag","isle","man","nation","country","banner","isle_of_man"]},"flag-india":{"a":"Flag: India","b":"1F1EE-1F1F3","j":["flag","in","nation","country","banner","india"]},"flag-british-indian-ocean-territory":{"a":"Flag: British Indian Ocean Territory","b":"1F1EE-1F1F4","j":["flag","british","indian","ocean","territory","nation","country","banner","british_indian_ocean_territory"]},"flag-iraq":{"a":"Flag: Iraq","b":"1F1EE-1F1F6","j":["flag","iq","nation","country","banner","iraq"]},"flag-iran":{"a":"Flag: Iran","b":"1F1EE-1F1F7","j":["flag","iran","islamic","republic","nation","country","banner"]},"flag-iceland":{"a":"Flag: Iceland","b":"1F1EE-1F1F8","j":["flag","is","nation","country","banner","iceland"]},"flag-italy":{"a":"Flag: Italy","b":"1F1EE-1F1F9","j":["flag","italy","nation","country","banner"]},"flag-jersey":{"a":"Flag: Jersey","b":"1F1EF-1F1EA","j":["flag","je","nation","country","banner","jersey"]},"flag-jamaica":{"a":"Flag: Jamaica","b":"1F1EF-1F1F2","j":["flag","jm","nation","country","banner","jamaica"]},"flag-jordan":{"a":"Flag: Jordan","b":"1F1EF-1F1F4","j":["flag","jo","nation","country","banner","jordan"]},"flag-japan":{"a":"Flag: Japan","b":"1F1EF-1F1F5","j":["flag","japanese","nation","country","banner","japan"]},"flag-kenya":{"a":"Flag: Kenya","b":"1F1F0-1F1EA","j":["flag","ke","nation","country","banner","kenya"]},"flag-kyrgyzstan":{"a":"Flag: Kyrgyzstan","b":"1F1F0-1F1EC","j":["flag","kg","nation","country","banner","kyrgyzstan"]},"flag-cambodia":{"a":"Flag: Cambodia","b":"1F1F0-1F1ED","j":["flag","kh","nation","country","banner","cambodia"]},"flag-kiribati":{"a":"Flag: Kiribati","b":"1F1F0-1F1EE","j":["flag","ki","nation","country","banner","kiribati"]},"flag-comoros":{"a":"Flag: Comoros","b":"1F1F0-1F1F2","j":["flag","km","nation","country","banner","comoros"]},"flag-st-kitts--nevis":{"a":"Flag: St. Kitts & Nevis","b":"1F1F0-1F1F3","j":["flag","flag_st_kitts_nevis","saint","kitts","nevis","nation","country","banner","st_kitts_nevis"]},"flag-north-korea":{"a":"Flag: North Korea","b":"1F1F0-1F1F5","j":["flag","north","korea","nation","country","banner","north_korea"]},"flag-south-korea":{"a":"Flag: South Korea","b":"1F1F0-1F1F7","j":["flag","south","korea","nation","country","banner","south_korea"]},"flag-kuwait":{"a":"Flag: Kuwait","b":"1F1F0-1F1FC","j":["flag","kw","nation","country","banner","kuwait"]},"flag-cayman-islands":{"a":"Flag: Cayman Islands","b":"1F1F0-1F1FE","j":["flag","cayman","islands","nation","country","banner","cayman_islands"]},"flag-kazakhstan":{"a":"Flag: Kazakhstan","b":"1F1F0-1F1FF","j":["flag","kz","nation","country","banner","kazakhstan"]},"flag-laos":{"a":"Flag: Laos","b":"1F1F1-1F1E6","j":["flag","lao","democratic","republic","nation","country","banner","laos"]},"flag-lebanon":{"a":"Flag: Lebanon","b":"1F1F1-1F1E7","j":["flag","lb","nation","country","banner","lebanon"]},"flag-st-lucia":{"a":"Flag: St. Lucia","b":"1F1F1-1F1E8","j":["flag","saint","lucia","nation","country","banner","st_lucia"]},"flag-liechtenstein":{"a":"Flag: Liechtenstein","b":"1F1F1-1F1EE","j":["flag","li","nation","country","banner","liechtenstein"]},"flag-sri-lanka":{"a":"Flag: Sri Lanka","b":"1F1F1-1F1F0","j":["flag","sri","lanka","nation","country","banner","sri_lanka"]},"flag-liberia":{"a":"Flag: Liberia","b":"1F1F1-1F1F7","j":["flag","lr","nation","country","banner","liberia"]},"flag-lesotho":{"a":"Flag: Lesotho","b":"1F1F1-1F1F8","j":["flag","ls","nation","country","banner","lesotho"]},"flag-lithuania":{"a":"Flag: Lithuania","b":"1F1F1-1F1F9","j":["flag","lt","nation","country","banner","lithuania"]},"flag-luxembourg":{"a":"Flag: Luxembourg","b":"1F1F1-1F1FA","j":["flag","lu","nation","country","banner","luxembourg"]},"flag-latvia":{"a":"Flag: Latvia","b":"1F1F1-1F1FB","j":["flag","lv","nation","country","banner","latvia"]},"flag-libya":{"a":"Flag: Libya","b":"1F1F1-1F1FE","j":["flag","ly","nation","country","banner","libya"]},"flag-morocco":{"a":"Flag: Morocco","b":"1F1F2-1F1E6","j":["flag","ma","nation","country","banner","morocco"]},"flag-monaco":{"a":"Flag: Monaco","b":"1F1F2-1F1E8","j":["flag","mc","nation","country","banner","monaco"]},"flag-moldova":{"a":"Flag: Moldova","b":"1F1F2-1F1E9","j":["flag","moldova","republic","nation","country","banner"]},"flag-montenegro":{"a":"Flag: Montenegro","b":"1F1F2-1F1EA","j":["flag","me","nation","country","banner","montenegro"]},"flag-st-martin":{"a":"Flag: St. Martin","b":"1F1F2-1F1EB","j":["flag"]},"flag-madagascar":{"a":"Flag: Madagascar","b":"1F1F2-1F1EC","j":["flag","mg","nation","country","banner","madagascar"]},"flag-marshall-islands":{"a":"Flag: Marshall Islands","b":"1F1F2-1F1ED","j":["flag","marshall","islands","nation","country","banner","marshall_islands"]},"flag-north-macedonia":{"a":"Flag: North Macedonia","b":"1F1F2-1F1F0","j":["flag","macedonia","nation","country","banner","north_macedonia"]},"flag-mali":{"a":"Flag: Mali","b":"1F1F2-1F1F1","j":["flag","ml","nation","country","banner","mali"]},"flag-myanmar-burma":{"a":"Flag: Myanmar (Burma)","b":"1F1F2-1F1F2","j":["flag","flag_myanmar","mm","nation","country","banner","myanmar"]},"flag-mongolia":{"a":"Flag: Mongolia","b":"1F1F2-1F1F3","j":["flag","mn","nation","country","banner","mongolia"]},"flag-macao-sar-china":{"a":"Flag: Macao Sar China","b":"1F1F2-1F1F4","j":["flag","macao","nation","country","banner","macao_sar_china"]},"flag-northern-mariana-islands":{"a":"Flag: Northern Mariana Islands","b":"1F1F2-1F1F5","j":["flag","northern","mariana","islands","nation","country","banner","northern_mariana_islands"]},"flag-martinique":{"a":"Flag: Martinique","b":"1F1F2-1F1F6","j":["flag","mq","nation","country","banner","martinique"]},"flag-mauritania":{"a":"Flag: Mauritania","b":"1F1F2-1F1F7","j":["flag","mr","nation","country","banner","mauritania"]},"flag-montserrat":{"a":"Flag: Montserrat","b":"1F1F2-1F1F8","j":["flag","ms","nation","country","banner","montserrat"]},"flag-malta":{"a":"Flag: Malta","b":"1F1F2-1F1F9","j":["flag","mt","nation","country","banner","malta"]},"flag-mauritius":{"a":"Flag: Mauritius","b":"1F1F2-1F1FA","j":["flag","mu","nation","country","banner","mauritius"]},"flag-maldives":{"a":"Flag: Maldives","b":"1F1F2-1F1FB","j":["flag","mv","nation","country","banner","maldives"]},"flag-malawi":{"a":"Flag: Malawi","b":"1F1F2-1F1FC","j":["flag","mw","nation","country","banner","malawi"]},"flag-mexico":{"a":"Flag: Mexico","b":"1F1F2-1F1FD","j":["flag","mx","nation","country","banner","mexico"]},"flag-malaysia":{"a":"Flag: Malaysia","b":"1F1F2-1F1FE","j":["flag","my","nation","country","banner","malaysia"]},"flag-mozambique":{"a":"Flag: Mozambique","b":"1F1F2-1F1FF","j":["flag","mz","nation","country","banner","mozambique"]},"flag-namibia":{"a":"Flag: Namibia","b":"1F1F3-1F1E6","j":["flag","na","nation","country","banner","namibia"]},"flag-new-caledonia":{"a":"Flag: New Caledonia","b":"1F1F3-1F1E8","j":["flag","new","caledonia","nation","country","banner","new_caledonia"]},"flag-niger":{"a":"Flag: Niger","b":"1F1F3-1F1EA","j":["flag","ne","nation","country","banner","niger"]},"flag-norfolk-island":{"a":"Flag: Norfolk Island","b":"1F1F3-1F1EB","j":["flag","norfolk","island","nation","country","banner","norfolk_island"]},"flag-nigeria":{"a":"Flag: Nigeria","b":"1F1F3-1F1EC","j":["flag","nation","country","banner","nigeria"]},"flag-nicaragua":{"a":"Flag: Nicaragua","b":"1F1F3-1F1EE","j":["flag","ni","nation","country","banner","nicaragua"]},"flag-netherlands":{"a":"Flag: Netherlands","b":"1F1F3-1F1F1","j":["flag","nl","nation","country","banner","netherlands"]},"flag-norway":{"a":"Flag: Norway","b":"1F1F3-1F1F4","j":["flag","no","nation","country","banner","norway"]},"flag-nepal":{"a":"Flag: Nepal","b":"1F1F3-1F1F5","j":["flag","np","nation","country","banner","nepal"]},"flag-nauru":{"a":"Flag: Nauru","b":"1F1F3-1F1F7","j":["flag","nr","nation","country","banner","nauru"]},"flag-niue":{"a":"Flag: Niue","b":"1F1F3-1F1FA","j":["flag","nu","nation","country","banner","niue"]},"flag-new-zealand":{"a":"Flag: New Zealand","b":"1F1F3-1F1FF","j":["flag","new","zealand","nation","country","banner","new_zealand"]},"flag-oman":{"a":"Flag: Oman","b":"1F1F4-1F1F2","j":["flag","om_symbol","nation","country","banner","oman"]},"flag-panama":{"a":"Flag: Panama","b":"1F1F5-1F1E6","j":["flag","pa","nation","country","banner","panama"]},"flag-peru":{"a":"Flag: Peru","b":"1F1F5-1F1EA","j":["flag","pe","nation","country","banner","peru"]},"flag-french-polynesia":{"a":"Flag: French Polynesia","b":"1F1F5-1F1EB","j":["flag","french","polynesia","nation","country","banner","french_polynesia"]},"flag-papua-new-guinea":{"a":"Flag: Papua New Guinea","b":"1F1F5-1F1EC","j":["flag","papua","new","guinea","nation","country","banner","papua_new_guinea"]},"flag-philippines":{"a":"Flag: Philippines","b":"1F1F5-1F1ED","j":["flag","ph","nation","country","banner","philippines"]},"flag-pakistan":{"a":"Flag: Pakistan","b":"1F1F5-1F1F0","j":["flag","pk","nation","country","banner","pakistan"]},"flag-poland":{"a":"Flag: Poland","b":"1F1F5-1F1F1","j":["flag","pl","nation","country","banner","poland"]},"flag-st-pierre--miquelon":{"a":"Flag: St. Pierre & Miquelon","b":"1F1F5-1F1F2","j":["flag","flag_st_pierre_miquelon","saint","pierre","miquelon","nation","country","banner","st_pierre_miquelon"]},"flag-pitcairn-islands":{"a":"Flag: Pitcairn Islands","b":"1F1F5-1F1F3","j":["flag","pitcairn","nation","country","banner","pitcairn_islands"]},"flag-puerto-rico":{"a":"Flag: Puerto Rico","b":"1F1F5-1F1F7","j":["flag","puerto","rico","nation","country","banner","puerto_rico"]},"flag-palestinian-territories":{"a":"Flag: Palestinian Territories","b":"1F1F5-1F1F8","j":["flag","palestine","palestinian","territories","nation","country","banner","palestinian_territories"]},"flag-portugal":{"a":"Flag: Portugal","b":"1F1F5-1F1F9","j":["flag","pt","nation","country","banner","portugal"]},"flag-palau":{"a":"Flag: Palau","b":"1F1F5-1F1FC","j":["flag","pw","nation","country","banner","palau"]},"flag-paraguay":{"a":"Flag: Paraguay","b":"1F1F5-1F1FE","j":["flag","py","nation","country","banner","paraguay"]},"flag-qatar":{"a":"Flag: Qatar","b":"1F1F6-1F1E6","j":["flag","qa","nation","country","banner","qatar"]},"flag-runion":{"a":"Flag: Réunion","b":"1F1F7-1F1EA","j":["flag","flag_reunion","réunion","nation","country","banner","reunion"]},"flag-romania":{"a":"Flag: Romania","b":"1F1F7-1F1F4","j":["flag","ro","nation","country","banner","romania"]},"flag-serbia":{"a":"Flag: Serbia","b":"1F1F7-1F1F8","j":["flag","rs","nation","country","banner","serbia"]},"flag-russia":{"a":"Flag: Russia","b":"1F1F7-1F1FA","j":["flag","russian","federation","nation","country","banner","russia"]},"flag-rwanda":{"a":"Flag: Rwanda","b":"1F1F7-1F1FC","j":["flag","rw","nation","country","banner","rwanda"]},"flag-saudi-arabia":{"a":"Flag: Saudi Arabia","b":"1F1F8-1F1E6","j":["flag","nation","country","banner","saudi_arabia"]},"flag-solomon-islands":{"a":"Flag: Solomon Islands","b":"1F1F8-1F1E7","j":["flag","solomon","islands","nation","country","banner","solomon_islands"]},"flag-seychelles":{"a":"Flag: Seychelles","b":"1F1F8-1F1E8","j":["flag","sc","nation","country","banner","seychelles"]},"flag-sudan":{"a":"Flag: Sudan","b":"1F1F8-1F1E9","j":["flag","sd","nation","country","banner","sudan"]},"flag-sweden":{"a":"Flag: Sweden","b":"1F1F8-1F1EA","j":["flag","se","nation","country","banner","sweden"]},"flag-singapore":{"a":"Flag: Singapore","b":"1F1F8-1F1EC","j":["flag","sg","nation","country","banner","singapore"]},"flag-st-helena":{"a":"Flag: St. Helena","b":"1F1F8-1F1ED","j":["flag","saint","helena","ascension","tristan","cunha","nation","country","banner","st_helena"]},"flag-slovenia":{"a":"Flag: Slovenia","b":"1F1F8-1F1EE","j":["flag","si","nation","country","banner","slovenia"]},"flag-svalbard--jan-mayen":{"a":"Flag: Svalbard & Jan Mayen","b":"1F1F8-1F1EF","j":["flag","flag_svalbard_jan_mayen"]},"flag-slovakia":{"a":"Flag: Slovakia","b":"1F1F8-1F1F0","j":["flag","sk","nation","country","banner","slovakia"]},"flag-sierra-leone":{"a":"Flag: Sierra Leone","b":"1F1F8-1F1F1","j":["flag","sierra","leone","nation","country","banner","sierra_leone"]},"flag-san-marino":{"a":"Flag: San Marino","b":"1F1F8-1F1F2","j":["flag","san","marino","nation","country","banner","san_marino"]},"flag-senegal":{"a":"Flag: Senegal","b":"1F1F8-1F1F3","j":["flag","sn","nation","country","banner","senegal"]},"flag-somalia":{"a":"Flag: Somalia","b":"1F1F8-1F1F4","j":["flag","so","nation","country","banner","somalia"]},"flag-suriname":{"a":"Flag: Suriname","b":"1F1F8-1F1F7","j":["flag","sr","nation","country","banner","suriname"]},"flag-south-sudan":{"a":"Flag: South Sudan","b":"1F1F8-1F1F8","j":["flag","south","sd","nation","country","banner","south_sudan"]},"flag-so-tom--prncipe":{"a":"Flag: São Tomé & Príncipe","b":"1F1F8-1F1F9","j":["flag","flag_sao_tome_principe","sao","tome","principe","nation","country","banner","sao_tome_principe"]},"flag-el-salvador":{"a":"Flag: El Salvador","b":"1F1F8-1F1FB","j":["flag","el","salvador","nation","country","banner","el_salvador"]},"flag-sint-maarten":{"a":"Flag: Sint Maarten","b":"1F1F8-1F1FD","j":["flag","sint","maarten","dutch","nation","country","banner","sint_maarten"]},"flag-syria":{"a":"Flag: Syria","b":"1F1F8-1F1FE","j":["flag","syrian","arab","republic","nation","country","banner","syria"]},"flag-eswatini":{"a":"Flag: Eswatini","b":"1F1F8-1F1FF","j":["flag","sz","nation","country","banner","eswatini"]},"flag-tristan-da-cunha":{"a":"Flag: Tristan Da Cunha","b":"1F1F9-1F1E6","j":["flag"]},"flag-turks--caicos-islands":{"a":"Flag: Turks & Caicos Islands","b":"1F1F9-1F1E8","j":["flag","flag_turks_caicos_islands","turks","caicos","islands","nation","country","banner","turks_caicos_islands"]},"flag-chad":{"a":"Flag: Chad","b":"1F1F9-1F1E9","j":["flag","td","nation","country","banner","chad"]},"flag-french-southern-territories":{"a":"Flag: French Southern Territories","b":"1F1F9-1F1EB","j":["flag","french","southern","territories","nation","country","banner","french_southern_territories"]},"flag-togo":{"a":"Flag: Togo","b":"1F1F9-1F1EC","j":["flag","tg","nation","country","banner","togo"]},"flag-thailand":{"a":"Flag: Thailand","b":"1F1F9-1F1ED","j":["flag","th","nation","country","banner","thailand"]},"flag-tajikistan":{"a":"Flag: Tajikistan","b":"1F1F9-1F1EF","j":["flag","tj","nation","country","banner","tajikistan"]},"flag-tokelau":{"a":"Flag: Tokelau","b":"1F1F9-1F1F0","j":["flag","tk","nation","country","banner","tokelau"]},"flag-timorleste":{"a":"Flag: Timor-Leste","b":"1F1F9-1F1F1","j":["flag","flag_timor_leste","timor","leste","nation","country","banner","timor_leste"]},"flag-turkmenistan":{"a":"Flag: Turkmenistan","b":"1F1F9-1F1F2","j":["flag","nation","country","banner","turkmenistan"]},"flag-tunisia":{"a":"Flag: Tunisia","b":"1F1F9-1F1F3","j":["flag","tn","nation","country","banner","tunisia"]},"flag-tonga":{"a":"Flag: Tonga","b":"1F1F9-1F1F4","j":["flag","to","nation","country","banner","tonga"]},"flag-turkey":{"a":"Flag: Turkey","b":"1F1F9-1F1F7","j":["flag","turkey","nation","country","banner"]},"flag-trinidad--tobago":{"a":"Flag: Trinidad & Tobago","b":"1F1F9-1F1F9","j":["flag","flag_trinidad_tobago","trinidad","tobago","nation","country","banner","trinidad_tobago"]},"flag-tuvalu":{"a":"Flag: Tuvalu","b":"1F1F9-1F1FB","j":["flag","nation","country","banner","tuvalu"]},"flag-taiwan":{"a":"Flag: Taiwan","b":"1F1F9-1F1FC","j":["flag","tw","nation","country","banner","taiwan"]},"flag-tanzania":{"a":"Flag: Tanzania","b":"1F1F9-1F1FF","j":["flag","tanzania","united","republic","nation","country","banner"]},"flag-ukraine":{"a":"Flag: Ukraine","b":"1F1FA-1F1E6","j":["flag","ua","nation","country","banner","ukraine"]},"flag-uganda":{"a":"Flag: Uganda","b":"1F1FA-1F1EC","j":["flag","ug","nation","country","banner","uganda"]},"flag-us-outlying-islands":{"a":"Flag: U.S. Outlying Islands","b":"1F1FA-1F1F2","j":["flag","flag_u_s_outlying_islands"]},"flag-united-nations":{"a":"Flag: United Nations","b":"1F1FA-1F1F3","j":["flag","un","banner"]},"flag-united-states":{"a":"Flag: United States","b":"1F1FA-1F1F8","j":["flag","united","states","america","nation","country","banner","united_states"]},"flag-uruguay":{"a":"Flag: Uruguay","b":"1F1FA-1F1FE","j":["flag","uy","nation","country","banner","uruguay"]},"flag-uzbekistan":{"a":"Flag: Uzbekistan","b":"1F1FA-1F1FF","j":["flag","uz","nation","country","banner","uzbekistan"]},"flag-vatican-city":{"a":"Flag: Vatican City","b":"1F1FB-1F1E6","j":["flag","vatican","city","nation","country","banner","vatican_city"]},"flag-st-vincent--grenadines":{"a":"Flag: St. Vincent & Grenadines","b":"1F1FB-1F1E8","j":["flag","flag_st_vincent_grenadines","saint","vincent","grenadines","nation","country","banner","st_vincent_grenadines"]},"flag-venezuela":{"a":"Flag: Venezuela","b":"1F1FB-1F1EA","j":["flag","ve","bolivarian","republic","nation","country","banner","venezuela"]},"flag-british-virgin-islands":{"a":"Flag: British Virgin Islands","b":"1F1FB-1F1EC","j":["flag","british","virgin","islands","bvi","nation","country","banner","british_virgin_islands"]},"flag-us-virgin-islands":{"a":"Flag: U.S. Virgin Islands","b":"1F1FB-1F1EE","j":["flag","flag_u_s_virgin_islands","virgin","islands","us","nation","country","banner","u_s_virgin_islands"]},"flag-vietnam":{"a":"Flag: Vietnam","b":"1F1FB-1F1F3","j":["flag","viet","nam","nation","country","banner","vietnam"]},"flag-vanuatu":{"a":"Flag: Vanuatu","b":"1F1FB-1F1FA","j":["flag","vu","nation","country","banner","vanuatu"]},"flag-wallis--futuna":{"a":"Flag: Wallis & Futuna","b":"1F1FC-1F1EB","j":["flag","flag_wallis_futuna","wallis","futuna","nation","country","banner","wallis_futuna"]},"flag-samoa":{"a":"Flag: Samoa","b":"1F1FC-1F1F8","j":["flag","ws","nation","country","banner","samoa"]},"flag-kosovo":{"a":"Flag: Kosovo","b":"1F1FD-1F1F0","j":["flag","xk","nation","country","banner","kosovo"]},"flag-yemen":{"a":"Flag: Yemen","b":"1F1FE-1F1EA","j":["flag","ye","nation","country","banner","yemen"]},"flag-mayotte":{"a":"Flag: Mayotte","b":"1F1FE-1F1F9","j":["flag","yt","nation","country","banner","mayotte"]},"flag-south-africa":{"a":"Flag: South Africa","b":"1F1FF-1F1E6","j":["flag","south","africa","nation","country","banner","south_africa"]},"flag-zambia":{"a":"Flag: Zambia","b":"1F1FF-1F1F2","j":["flag","zm","nation","country","banner","zambia"]},"flag-zimbabwe":{"a":"Flag: Zimbabwe","b":"1F1FF-1F1FC","j":["flag","zw","nation","country","banner","zimbabwe"]},"flag-england":{"a":"Flag: England","b":"1F3F4-E0067-E0062-E0065-E006E-E0067-E007F","j":["flag","english"]},"flag-scotland":{"a":"Flag: Scotland","b":"1F3F4-E0067-E0062-E0073-E0063-E0074-E007F","j":["flag","scottish"]},"flag-wales":{"a":"Flag: Wales","b":"1F3F4-E0067-E0062-E0077-E006C-E0073-E007F","j":["flag","welsh"]}},"aliases":{}}
\ No newline at end of file
+{"compressed":true,"categories":[{"id":"smileys_&_emotion","name":"Smileys & Emotion","emojis":["grinning-face","grinning-face-with-big-eyes","grinning-face-with-smiling-eyes","beaming-face-with-smiling-eyes","grinning-squinting-face","grinning-face-with-sweat","rolling-on-the-floor-laughing","face-with-tears-of-joy","slightly-smiling-face","upsidedown-face","melting-face","winking-face","smiling-face-with-smiling-eyes","smiling-face-with-halo","smiling-face-with-hearts","smiling-face-with-hearteyes","starstruck","face-blowing-a-kiss","kissing-face","smiling-face","kissing-face-with-closed-eyes","kissing-face-with-smiling-eyes","smiling-face-with-tear","face-savoring-food","face-with-tongue","winking-face-with-tongue","zany-face","squinting-face-with-tongue","moneymouth-face","smiling-face-with-open-hands","face-with-hand-over-mouth","face-with-open-eyes-and-hand-over-mouth","face-with-peeking-eye","shushing-face","thinking-face","saluting-face","zippermouth-face","face-with-raised-eyebrow","neutral-face","expressionless-face","face-without-mouth","dotted-line-face","face-in-clouds","smirking-face","unamused-face","face-with-rolling-eyes","grimacing-face","face-exhaling","lying-face","relieved-face","pensive-face","sleepy-face","drooling-face","sleeping-face","face-with-medical-mask","face-with-thermometer","face-with-headbandage","nauseated-face","face-vomiting","sneezing-face","hot-face","cold-face","woozy-face","face-with-crossedout-eyes","face-with-spiral-eyes","exploding-head","cowboy-hat-face","partying-face","disguised-face","smiling-face-with-sunglasses","nerd-face","face-with-monocle","confused-face","face-with-diagonal-mouth","worried-face","slightly-frowning-face","frowning-face","face-with-open-mouth","hushed-face","astonished-face","flushed-face","pleading-face","face-holding-back-tears","frowning-face-with-open-mouth","anguished-face","fearful-face","anxious-face-with-sweat","sad-but-relieved-face","crying-face","loudly-crying-face","face-screaming-in-fear","confounded-face","persevering-face","disappointed-face","downcast-face-with-sweat","weary-face","tired-face","yawning-face","face-with-steam-from-nose","pouting-face","angry-face","face-with-symbols-on-mouth","smiling-face-with-horns","angry-face-with-horns","skull","skull-and-crossbones","pile-of-poo","clown-face","ogre","goblin","ghost","alien","alien-monster","robot","grinning-cat","grinning-cat-with-smiling-eyes","cat-with-tears-of-joy","smiling-cat-with-hearteyes","cat-with-wry-smile","kissing-cat","weary-cat","crying-cat","pouting-cat","seenoevil-monkey","hearnoevil-monkey","speaknoevil-monkey","kiss-mark","love-letter","heart-with-arrow","heart-with-ribbon","sparkling-heart","growing-heart","beating-heart","revolving-hearts","two-hearts","heart-decoration","heart-exclamation","broken-heart","heart-on-fire","mending-heart","red-heart","orange-heart","yellow-heart","green-heart","blue-heart","purple-heart","brown-heart","black-heart","white-heart","hundred-points","anger-symbol","collision","dizzy","sweat-droplets","dashing-away","hole","bomb","speech-balloon","eye-in-speech-bubble","left-speech-bubble","right-anger-bubble","thought-balloon","zzz"]},{"id":"people_&_body","name":"People & Body","emojis":["waving-hand","raised-back-of-hand","hand-with-fingers-splayed","raised-hand","vulcan-salute","rightwards-hand","leftwards-hand","palm-down-hand","palm-up-hand","ok-hand","pinched-fingers","pinching-hand","victory-hand","crossed-fingers","hand-with-index-finger-and-thumb-crossed","loveyou-gesture","sign-of-the-horns","call-me-hand","backhand-index-pointing-left","backhand-index-pointing-right","backhand-index-pointing-up","middle-finger","backhand-index-pointing-down","index-pointing-up","index-pointing-at-the-viewer","thumbs-up","thumbs-down","raised-fist","oncoming-fist","leftfacing-fist","rightfacing-fist","clapping-hands","raising-hands","heart-hands","open-hands","palms-up-together","handshake","folded-hands","writing-hand","nail-polish","selfie","flexed-biceps","mechanical-arm","mechanical-leg","leg","foot","ear","ear-with-hearing-aid","nose","brain","anatomical-heart","lungs","tooth","bone","eyes","eye","tongue","mouth","biting-lip","baby","child","boy","girl","person","person-blond-hair","man","person-beard","man-beard","woman-beard","man-red-hair","man-curly-hair","man-white-hair","man-bald","woman","woman-red-hair","person-red-hair","woman-curly-hair","person-curly-hair","woman-white-hair","person-white-hair","woman-bald","person-bald","woman-blond-hair","man-blond-hair","older-person","old-man","old-woman","person-frowning","man-frowning","woman-frowning","person-pouting","man-pouting","woman-pouting","person-gesturing-no","man-gesturing-no","woman-gesturing-no","person-gesturing-ok","man-gesturing-ok","woman-gesturing-ok","person-tipping-hand","man-tipping-hand","woman-tipping-hand","person-raising-hand","man-raising-hand","woman-raising-hand","deaf-person","deaf-man","deaf-woman","person-bowing","man-bowing","woman-bowing","person-facepalming","man-facepalming","woman-facepalming","person-shrugging","man-shrugging","woman-shrugging","health-worker","man-health-worker","woman-health-worker","student","man-student","woman-student","teacher","man-teacher","woman-teacher","judge","man-judge","woman-judge","farmer","man-farmer","woman-farmer","cook","man-cook","woman-cook","mechanic","man-mechanic","woman-mechanic","factory-worker","man-factory-worker","woman-factory-worker","office-worker","man-office-worker","woman-office-worker","scientist","man-scientist","woman-scientist","technologist","man-technologist","woman-technologist","singer","man-singer","woman-singer","artist","man-artist","woman-artist","pilot","man-pilot","woman-pilot","astronaut","man-astronaut","woman-astronaut","firefighter","man-firefighter","woman-firefighter","police-officer","man-police-officer","woman-police-officer","detective","man-detective","woman-detective","guard","man-guard","woman-guard","ninja","construction-worker","man-construction-worker","woman-construction-worker","person-with-crown","prince","princess","person-wearing-turban","man-wearing-turban","woman-wearing-turban","person-with-skullcap","woman-with-headscarf","person-in-tuxedo","man-in-tuxedo","woman-in-tuxedo","person-with-veil","man-with-veil","woman-with-veil","pregnant-woman","pregnant-man","pregnant-person","breastfeeding","woman-feeding-baby","man-feeding-baby","person-feeding-baby","baby-angel","santa-claus","mrs-claus","mx-claus","superhero","man-superhero","woman-superhero","supervillain","man-supervillain","woman-supervillain","mage","man-mage","woman-mage","fairy","man-fairy","woman-fairy","vampire","man-vampire","woman-vampire","merperson","merman","mermaid","elf","man-elf","woman-elf","genie","man-genie","woman-genie","zombie","man-zombie","woman-zombie","troll","person-getting-massage","man-getting-massage","woman-getting-massage","person-getting-haircut","man-getting-haircut","woman-getting-haircut","person-walking","man-walking","woman-walking","person-standing","man-standing","woman-standing","person-kneeling","man-kneeling","woman-kneeling","person-with-white-cane","man-with-white-cane","woman-with-white-cane","person-in-motorized-wheelchair","man-in-motorized-wheelchair","woman-in-motorized-wheelchair","person-in-manual-wheelchair","man-in-manual-wheelchair","woman-in-manual-wheelchair","person-running","man-running","woman-running","woman-dancing","man-dancing","person-in-suit-levitating","people-with-bunny-ears","men-with-bunny-ears","women-with-bunny-ears","person-in-steamy-room","man-in-steamy-room","woman-in-steamy-room","person-climbing","man-climbing","woman-climbing","person-fencing","horse-racing","skier","snowboarder","person-golfing","man-golfing","woman-golfing","person-surfing","man-surfing","woman-surfing","person-rowing-boat","man-rowing-boat","woman-rowing-boat","person-swimming","man-swimming","woman-swimming","person-bouncing-ball","man-bouncing-ball","woman-bouncing-ball","person-lifting-weights","man-lifting-weights","woman-lifting-weights","person-biking","man-biking","woman-biking","person-mountain-biking","man-mountain-biking","woman-mountain-biking","person-cartwheeling","man-cartwheeling","woman-cartwheeling","people-wrestling","men-wrestling","women-wrestling","person-playing-water-polo","man-playing-water-polo","woman-playing-water-polo","person-playing-handball","man-playing-handball","woman-playing-handball","person-juggling","man-juggling","woman-juggling","person-in-lotus-position","man-in-lotus-position","woman-in-lotus-position","person-taking-bath","person-in-bed","people-holding-hands","women-holding-hands","woman-and-man-holding-hands","men-holding-hands","kiss","kiss-woman-man","kiss-man-man","kiss-woman-woman","couple-with-heart","couple-with-heart-woman-man","couple-with-heart-man-man","couple-with-heart-woman-woman","family","family-man-woman-boy","family-man-woman-girl","family-man-woman-girl-boy","family-man-woman-boy-boy","family-man-woman-girl-girl","family-man-man-boy","family-man-man-girl","family-man-man-girl-boy","family-man-man-boy-boy","family-man-man-girl-girl","family-woman-woman-boy","family-woman-woman-girl","family-woman-woman-girl-boy","family-woman-woman-boy-boy","family-woman-woman-girl-girl","family-man-boy","family-man-boy-boy","family-man-girl","family-man-girl-boy","family-man-girl-girl","family-woman-boy","family-woman-boy-boy","family-woman-girl","family-woman-girl-boy","family-woman-girl-girl","speaking-head","bust-in-silhouette","busts-in-silhouette","people-hugging","footprints"]},{"id":"animals_&_nature","name":"Animals & Nature","emojis":["monkey-face","monkey","gorilla","orangutan","dog-face","dog","guide-dog","service-dog","poodle","wolf","fox","raccoon","cat-face","cat","black-cat","lion","tiger-face","tiger","leopard","horse-face","horse","unicorn","zebra","deer","bison","cow-face","ox","water-buffalo","cow","pig-face","pig","boar","pig-nose","ram","ewe","goat","camel","twohump-camel","llama","giraffe","elephant","mammoth","rhinoceros","hippopotamus","mouse-face","mouse","rat","hamster","rabbit-face","rabbit","chipmunk","beaver","hedgehog","bat","bear","polar-bear","koala","panda","sloth","otter","skunk","kangaroo","badger","paw-prints","turkey","chicken","rooster","hatching-chick","baby-chick","frontfacing-baby-chick","bird","penguin","dove","eagle","duck","swan","owl","dodo","feather","flamingo","peacock","parrot","frog","crocodile","turtle","lizard","snake","dragon-face","dragon","sauropod","trex","spouting-whale","whale","dolphin","seal","fish","tropical-fish","blowfish","shark","octopus","spiral-shell","coral","snail","butterfly","bug","ant","honeybee","beetle","lady-beetle","cricket","cockroach","spider","spider-web","scorpion","mosquito","fly","worm","microbe","bouquet","cherry-blossom","white-flower","lotus","rosette","rose","wilted-flower","hibiscus","sunflower","blossom","tulip","seedling","potted-plant","evergreen-tree","deciduous-tree","palm-tree","cactus","sheaf-of-rice","herb","shamrock","four-leaf-clover","maple-leaf","fallen-leaf","leaf-fluttering-in-wind","empty-nest","nest-with-eggs"]},{"id":"food_&_drink","name":"Food & Drink","emojis":["grapes","melon","watermelon","tangerine","lemon","banana","pineapple","mango","red-apple","green-apple","pear","peach","cherries","strawberry","blueberries","kiwi-fruit","tomato","olive","coconut","avocado","eggplant","potato","carrot","ear-of-corn","hot-pepper","bell-pepper","cucumber","leafy-green","broccoli","garlic","onion","mushroom","peanuts","beans","chestnut","bread","croissant","baguette-bread","flatbread","pretzel","bagel","pancakes","waffle","cheese-wedge","meat-on-bone","poultry-leg","cut-of-meat","bacon","hamburger","french-fries","pizza","hot-dog","sandwich","taco","burrito","tamale","stuffed-flatbread","falafel","egg","cooking","shallow-pan-of-food","pot-of-food","fondue","bowl-with-spoon","green-salad","popcorn","butter","salt","canned-food","bento-box","rice-cracker","rice-ball","cooked-rice","curry-rice","steaming-bowl","spaghetti","roasted-sweet-potato","oden","sushi","fried-shrimp","fish-cake-with-swirl","moon-cake","dango","dumpling","fortune-cookie","takeout-box","crab","lobster","shrimp","squid","oyster","soft-ice-cream","shaved-ice","ice-cream","doughnut","cookie","birthday-cake","shortcake","cupcake","pie","chocolate-bar","candy","lollipop","custard","honey-pot","baby-bottle","glass-of-milk","hot-beverage","teapot","teacup-without-handle","sake","bottle-with-popping-cork","wine-glass","cocktail-glass","tropical-drink","beer-mug","clinking-beer-mugs","clinking-glasses","tumbler-glass","pouring-liquid","cup-with-straw","bubble-tea","beverage-box","mate","ice","chopsticks","fork-and-knife-with-plate","fork-and-knife","spoon","kitchen-knife","jar","amphora"]},{"id":"travel_&_places","name":"Travel & Places","emojis":["globe-showing-europeafrica","globe-showing-americas","globe-showing-asiaaustralia","globe-with-meridians","world-map","map-of-japan","compass","snowcapped-mountain","mountain","volcano","mount-fuji","camping","beach-with-umbrella","desert","desert-island","national-park","stadium","classical-building","building-construction","brick","rock","wood","hut","houses","derelict-house","house","house-with-garden","office-building","japanese-post-office","post-office","hospital","bank","hotel","love-hotel","convenience-store","school","department-store","factory","japanese-castle","castle","wedding","tokyo-tower","statue-of-liberty","church","mosque","hindu-temple","synagogue","shinto-shrine","kaaba","fountain","tent","foggy","night-with-stars","cityscape","sunrise-over-mountains","sunrise","cityscape-at-dusk","sunset","bridge-at-night","hot-springs","carousel-horse","playground-slide","ferris-wheel","roller-coaster","barber-pole","circus-tent","locomotive","railway-car","highspeed-train","bullet-train","train","metro","light-rail","station","tram","monorail","mountain-railway","tram-car","bus","oncoming-bus","trolleybus","minibus","ambulance","fire-engine","police-car","oncoming-police-car","taxi","oncoming-taxi","automobile","oncoming-automobile","sport-utility-vehicle","pickup-truck","delivery-truck","articulated-lorry","tractor","racing-car","motorcycle","motor-scooter","manual-wheelchair","motorized-wheelchair","auto-rickshaw","bicycle","kick-scooter","skateboard","roller-skate","bus-stop","motorway","railway-track","oil-drum","fuel-pump","wheel","police-car-light","horizontal-traffic-light","vertical-traffic-light","stop-sign","construction","anchor","ring-buoy","sailboat","canoe","speedboat","passenger-ship","ferry","motor-boat","ship","airplane","small-airplane","airplane-departure","airplane-arrival","parachute","seat","helicopter","suspension-railway","mountain-cableway","aerial-tramway","satellite","rocket","flying-saucer","bellhop-bell","luggage","hourglass-done","hourglass-not-done","watch","alarm-clock","stopwatch","timer-clock","mantelpiece-clock","twelve-oclock","twelvethirty","one-oclock","onethirty","two-oclock","twothirty","three-oclock","threethirty","four-oclock","fourthirty","five-oclock","fivethirty","six-oclock","sixthirty","seven-oclock","seventhirty","eight-oclock","eightthirty","nine-oclock","ninethirty","ten-oclock","tenthirty","eleven-oclock","eleventhirty","new-moon","waxing-crescent-moon","first-quarter-moon","waxing-gibbous-moon","full-moon","waning-gibbous-moon","last-quarter-moon","waning-crescent-moon","crescent-moon","new-moon-face","first-quarter-moon-face","last-quarter-moon-face","thermometer","sun","full-moon-face","sun-with-face","ringed-planet","star","glowing-star","shooting-star","milky-way","cloud","sun-behind-cloud","cloud-with-lightning-and-rain","sun-behind-small-cloud","sun-behind-large-cloud","sun-behind-rain-cloud","cloud-with-rain","cloud-with-snow","cloud-with-lightning","tornado","fog","wind-face","cyclone","rainbow","closed-umbrella","umbrella","umbrella-with-rain-drops","umbrella-on-ground","high-voltage","snowflake","snowman","snowman-without-snow","comet","fire","droplet","water-wave"]},{"id":"activities","name":"Activities","emojis":["jackolantern","christmas-tree","fireworks","sparkler","firecracker","sparkles","balloon","party-popper","confetti-ball","tanabata-tree","pine-decoration","japanese-dolls","carp-streamer","wind-chime","moon-viewing-ceremony","red-envelope","ribbon","wrapped-gift","reminder-ribbon","admission-tickets","ticket","military-medal","trophy","sports-medal","1st-place-medal","2nd-place-medal","3rd-place-medal","soccer-ball","baseball","softball","basketball","volleyball","american-football","rugby-football","tennis","flying-disc","bowling","cricket-game","field-hockey","ice-hockey","lacrosse","ping-pong","badminton","boxing-glove","martial-arts-uniform","goal-net","flag-in-hole","ice-skate","fishing-pole","diving-mask","running-shirt","skis","sled","curling-stone","bullseye","yoyo","kite","pool-8-ball","crystal-ball","magic-wand","nazar-amulet","hamsa","video-game","joystick","slot-machine","game-die","puzzle-piece","teddy-bear","piata","mirror-ball","nesting-dolls","spade-suit","heart-suit","diamond-suit","club-suit","chess-pawn","joker","mahjong-red-dragon","flower-playing-cards","performing-arts","framed-picture","artist-palette","thread","sewing-needle","yarn","knot"]},{"id":"objects","name":"Objects","emojis":["glasses","sunglasses","goggles","lab-coat","safety-vest","necktie","tshirt","jeans","scarf","gloves","coat","socks","dress","kimono","sari","onepiece-swimsuit","briefs","shorts","bikini","womans-clothes","purse","handbag","clutch-bag","shopping-bags","backpack","thong-sandal","mans-shoe","running-shoe","hiking-boot","flat-shoe","highheeled-shoe","womans-sandal","ballet-shoes","womans-boot","crown","womans-hat","top-hat","graduation-cap","billed-cap","military-helmet","rescue-workers-helmet","prayer-beads","lipstick","ring","gem-stone","muted-speaker","speaker-low-volume","speaker-medium-volume","speaker-high-volume","loudspeaker","megaphone","postal-horn","bell","bell-with-slash","musical-score","musical-note","musical-notes","studio-microphone","level-slider","control-knobs","microphone","headphone","radio","saxophone","accordion","guitar","musical-keyboard","trumpet","violin","banjo","drum","long-drum","mobile-phone","mobile-phone-with-arrow","telephone","telephone-receiver","pager","fax-machine","battery","low-battery","electric-plug","laptop","desktop-computer","printer","keyboard","computer-mouse","trackball","computer-disk","floppy-disk","optical-disk","dvd","abacus","movie-camera","film-frames","film-projector","clapper-board","television","camera","camera-with-flash","video-camera","videocassette","magnifying-glass-tilted-left","magnifying-glass-tilted-right","candle","light-bulb","flashlight","red-paper-lantern","diya-lamp","notebook-with-decorative-cover","closed-book","open-book","green-book","blue-book","orange-book","books","notebook","ledger","page-with-curl","scroll","page-facing-up","newspaper","rolledup-newspaper","bookmark-tabs","bookmark","label","money-bag","coin","yen-banknote","dollar-banknote","euro-banknote","pound-banknote","money-with-wings","credit-card","receipt","chart-increasing-with-yen","envelope","email","incoming-envelope","envelope-with-arrow","outbox-tray","inbox-tray","package","closed-mailbox-with-raised-flag","closed-mailbox-with-lowered-flag","open-mailbox-with-raised-flag","open-mailbox-with-lowered-flag","postbox","ballot-box-with-ballot","pencil","black-nib","fountain-pen","pen","paintbrush","crayon","memo","briefcase","file-folder","open-file-folder","card-index-dividers","calendar","tearoff-calendar","spiral-notepad","spiral-calendar","card-index","chart-increasing","chart-decreasing","bar-chart","clipboard","pushpin","round-pushpin","paperclip","linked-paperclips","straight-ruler","triangular-ruler","scissors","card-file-box","file-cabinet","wastebasket","locked","unlocked","locked-with-pen","locked-with-key","key","old-key","hammer","axe","pick","hammer-and-pick","hammer-and-wrench","dagger","crossed-swords","water-pistol","boomerang","bow-and-arrow","shield","carpentry-saw","wrench","screwdriver","nut-and-bolt","gear","clamp","balance-scale","white-cane","link","chains","hook","toolbox","magnet","ladder","alembic","test-tube","petri-dish","dna","microscope","telescope","satellite-antenna","syringe","drop-of-blood","pill","adhesive-bandage","crutch","stethoscope","xray","door","elevator","mirror","window","bed","couch-and-lamp","chair","toilet","plunger","shower","bathtub","mouse-trap","razor","lotion-bottle","safety-pin","broom","basket","roll-of-paper","bucket","soap","bubbles","toothbrush","sponge","fire-extinguisher","shopping-cart","cigarette","coffin","headstone","funeral-urn","moai","placard","identification-card"]},{"id":"symbols","name":"Symbols","emojis":["atm-sign","litter-in-bin-sign","potable-water","wheelchair-symbol","mens-room","womens-room","restroom","baby-symbol","water-closet","passport-control","customs","baggage-claim","left-luggage","warning","children-crossing","no-entry","prohibited","no-bicycles","no-smoking","no-littering","nonpotable-water","no-pedestrians","no-mobile-phones","no-one-under-eighteen","radioactive","biohazard","up-arrow","upright-arrow","right-arrow","downright-arrow","down-arrow","downleft-arrow","left-arrow","upleft-arrow","updown-arrow","leftright-arrow","right-arrow-curving-left","left-arrow-curving-right","right-arrow-curving-up","right-arrow-curving-down","clockwise-vertical-arrows","counterclockwise-arrows-button","back-arrow","end-arrow","on-arrow","soon-arrow","top-arrow","place-of-worship","atom-symbol","om","star-of-david","wheel-of-dharma","yin-yang","latin-cross","orthodox-cross","star-and-crescent","peace-symbol","menorah","dotted-sixpointed-star","aries","taurus","gemini","cancer","leo","virgo","libra","scorpio","sagittarius","capricorn","aquarius","pisces","ophiuchus","shuffle-tracks-button","repeat-button","repeat-single-button","play-button","fastforward-button","next-track-button","play-or-pause-button","reverse-button","fast-reverse-button","last-track-button","upwards-button","fast-up-button","downwards-button","fast-down-button","pause-button","stop-button","record-button","eject-button","cinema","dim-button","bright-button","antenna-bars","vibration-mode","mobile-phone-off","female-sign","male-sign","transgender-symbol","multiply","plus","minus","divide","heavy-equals-sign","infinity","double-exclamation-mark","exclamation-question-mark","red-question-mark","white-question-mark","white-exclamation-mark","red-exclamation-mark","wavy-dash","currency-exchange","heavy-dollar-sign","medical-symbol","recycling-symbol","fleurdelis","trident-emblem","name-badge","japanese-symbol-for-beginner","hollow-red-circle","check-mark-button","check-box-with-check","check-mark","cross-mark","cross-mark-button","curly-loop","double-curly-loop","part-alternation-mark","eightspoked-asterisk","eightpointed-star","sparkle","copyright","registered","trade-mark","keycap","keycap","keycap-0","keycap-1","keycap-2","keycap-3","keycap-4","keycap-5","keycap-6","keycap-7","keycap-8","keycap-9","keycap-10","input-latin-uppercase","input-latin-lowercase","input-numbers","input-symbols","input-latin-letters","a-button-blood-type","ab-button-blood-type","b-button-blood-type","cl-button","cool-button","free-button","information","id-button","circled-m","new-button","ng-button","o-button-blood-type","ok-button","p-button","sos-button","up-button","vs-button","japanese-here-button","japanese-service-charge-button","japanese-monthly-amount-button","japanese-not-free-of-charge-button","japanese-reserved-button","japanese-bargain-button","japanese-discount-button","japanese-free-of-charge-button","japanese-prohibited-button","japanese-acceptable-button","japanese-application-button","japanese-passing-grade-button","japanese-vacancy-button","japanese-congratulations-button","japanese-secret-button","japanese-open-for-business-button","japanese-no-vacancy-button","red-circle","orange-circle","yellow-circle","green-circle","blue-circle","purple-circle","brown-circle","black-circle","white-circle","red-square","orange-square","yellow-square","green-square","blue-square","purple-square","brown-square","black-large-square","white-large-square","black-medium-square","white-medium-square","black-mediumsmall-square","white-mediumsmall-square","black-small-square","white-small-square","large-orange-diamond","large-blue-diamond","small-orange-diamond","small-blue-diamond","red-triangle-pointed-up","red-triangle-pointed-down","diamond-with-a-dot","radio-button","white-square-button","black-square-button"]},{"id":"flags","name":"Flags","emojis":["chequered-flag","triangular-flag","crossed-flags","black-flag","white-flag","rainbow-flag","transgender-flag","pirate-flag","flag-ascension-island","flag-andorra","flag-united-arab-emirates","flag-afghanistan","flag-antigua--barbuda","flag-anguilla","flag-albania","flag-armenia","flag-angola","flag-antarctica","flag-argentina","flag-american-samoa","flag-austria","flag-australia","flag-aruba","flag-land-islands","flag-azerbaijan","flag-bosnia--herzegovina","flag-barbados","flag-bangladesh","flag-belgium","flag-burkina-faso","flag-bulgaria","flag-bahrain","flag-burundi","flag-benin","flag-st-barthlemy","flag-bermuda","flag-brunei","flag-bolivia","flag-caribbean-netherlands","flag-brazil","flag-bahamas","flag-bhutan","flag-bouvet-island","flag-botswana","flag-belarus","flag-belize","flag-canada","flag-cocos-keeling-islands","flag-congo--kinshasa","flag-central-african-republic","flag-congo--brazzaville","flag-switzerland","flag-cte-divoire","flag-cook-islands","flag-chile","flag-cameroon","flag-china","flag-colombia","flag-clipperton-island","flag-costa-rica","flag-cuba","flag-cape-verde","flag-curaao","flag-christmas-island","flag-cyprus","flag-czechia","flag-germany","flag-diego-garcia","flag-djibouti","flag-denmark","flag-dominica","flag-dominican-republic","flag-algeria","flag-ceuta--melilla","flag-ecuador","flag-estonia","flag-egypt","flag-western-sahara","flag-eritrea","flag-spain","flag-ethiopia","flag-european-union","flag-finland","flag-fiji","flag-falkland-islands","flag-micronesia","flag-faroe-islands","flag-france","flag-gabon","flag-united-kingdom","flag-grenada","flag-georgia","flag-french-guiana","flag-guernsey","flag-ghana","flag-gibraltar","flag-greenland","flag-gambia","flag-guinea","flag-guadeloupe","flag-equatorial-guinea","flag-greece","flag-south-georgia--south-sandwich-islands","flag-guatemala","flag-guam","flag-guineabissau","flag-guyana","flag-hong-kong-sar-china","flag-heard--mcdonald-islands","flag-honduras","flag-croatia","flag-haiti","flag-hungary","flag-canary-islands","flag-indonesia","flag-ireland","flag-israel","flag-isle-of-man","flag-india","flag-british-indian-ocean-territory","flag-iraq","flag-iran","flag-iceland","flag-italy","flag-jersey","flag-jamaica","flag-jordan","flag-japan","flag-kenya","flag-kyrgyzstan","flag-cambodia","flag-kiribati","flag-comoros","flag-st-kitts--nevis","flag-north-korea","flag-south-korea","flag-kuwait","flag-cayman-islands","flag-kazakhstan","flag-laos","flag-lebanon","flag-st-lucia","flag-liechtenstein","flag-sri-lanka","flag-liberia","flag-lesotho","flag-lithuania","flag-luxembourg","flag-latvia","flag-libya","flag-morocco","flag-monaco","flag-moldova","flag-montenegro","flag-st-martin","flag-madagascar","flag-marshall-islands","flag-north-macedonia","flag-mali","flag-myanmar-burma","flag-mongolia","flag-macao-sar-china","flag-northern-mariana-islands","flag-martinique","flag-mauritania","flag-montserrat","flag-malta","flag-mauritius","flag-maldives","flag-malawi","flag-mexico","flag-malaysia","flag-mozambique","flag-namibia","flag-new-caledonia","flag-niger","flag-norfolk-island","flag-nigeria","flag-nicaragua","flag-netherlands","flag-norway","flag-nepal","flag-nauru","flag-niue","flag-new-zealand","flag-oman","flag-panama","flag-peru","flag-french-polynesia","flag-papua-new-guinea","flag-philippines","flag-pakistan","flag-poland","flag-st-pierre--miquelon","flag-pitcairn-islands","flag-puerto-rico","flag-palestinian-territories","flag-portugal","flag-palau","flag-paraguay","flag-qatar","flag-runion","flag-romania","flag-serbia","flag-russia","flag-rwanda","flag-saudi-arabia","flag-solomon-islands","flag-seychelles","flag-sudan","flag-sweden","flag-singapore","flag-st-helena","flag-slovenia","flag-svalbard--jan-mayen","flag-slovakia","flag-sierra-leone","flag-san-marino","flag-senegal","flag-somalia","flag-suriname","flag-south-sudan","flag-so-tom--prncipe","flag-el-salvador","flag-sint-maarten","flag-syria","flag-eswatini","flag-tristan-da-cunha","flag-turks--caicos-islands","flag-chad","flag-french-southern-territories","flag-togo","flag-thailand","flag-tajikistan","flag-tokelau","flag-timorleste","flag-turkmenistan","flag-tunisia","flag-tonga","flag-turkey","flag-trinidad--tobago","flag-tuvalu","flag-taiwan","flag-tanzania","flag-ukraine","flag-uganda","flag-us-outlying-islands","flag-united-nations","flag-united-states","flag-uruguay","flag-uzbekistan","flag-vatican-city","flag-st-vincent--grenadines","flag-venezuela","flag-british-virgin-islands","flag-us-virgin-islands","flag-vietnam","flag-vanuatu","flag-wallis--futuna","flag-samoa","flag-kosovo","flag-yemen","flag-mayotte","flag-south-africa","flag-zambia","flag-zimbabwe","flag-england","flag-scotland","flag-wales"]}],"emojis":{"grinning-face":{"a":"Grinning Face","b":"1F600","j":["face","grin","smile","happy","joy",":D"]},"grinning-face-with-big-eyes":{"a":"Grinning Face with Big Eyes","b":"1F603","j":["face","mouth","open","smile","happy","joy","haha",":D",":)","funny"]},"grinning-face-with-smiling-eyes":{"a":"Grinning Face with Smiling Eyes","b":"1F604","j":["eye","face","mouth","open","smile","happy","joy","funny","haha","laugh","like",":D",":)"]},"beaming-face-with-smiling-eyes":{"a":"Beaming Face with Smiling Eyes","b":"1F601","j":["eye","face","grin","smile","happy","joy","kawaii"]},"grinning-squinting-face":{"a":"Grinning Squinting Face","b":"1F606","j":["face","laugh","mouth","satisfied","smile","happy","joy","lol","haha","glad","XD"]},"grinning-face-with-sweat":{"a":"Grinning Face with Sweat","b":"1F605","j":["cold","face","open","smile","sweat","hot","happy","laugh","relief"]},"rolling-on-the-floor-laughing":{"a":"Rolling on the Floor Laughing","b":"1F923","j":["face","floor","laugh","rofl","rolling","rotfl","laughing","lol","haha"]},"face-with-tears-of-joy":{"a":"Face with Tears of Joy","b":"1F602","j":["face","joy","laugh","tear","cry","tears","weep","happy","happytears","haha"]},"slightly-smiling-face":{"a":"Slightly Smiling Face","b":"1F642","j":["face","smile"]},"upsidedown-face":{"a":"Upside-Down Face","b":"1F643","j":["face","upside-down","upside_down_face","flipped","silly","smile"]},"melting-face":{"a":"⊛ Melting Face","b":"1FAE0","j":["disappear","dissolve","liquid","melt"]},"winking-face":{"a":"Winking Face","b":"1F609","j":["face","wink","happy","mischievous","secret",";)","smile","eye"]},"smiling-face-with-smiling-eyes":{"a":"Smiling Face with Smiling Eyes","b":"1F60A","j":["blush","eye","face","smile","happy","flushed","crush","embarrassed","shy","joy"]},"smiling-face-with-halo":{"a":"Smiling Face with Halo","b":"1F607","j":["angel","face","fantasy","halo","innocent","heaven"]},"smiling-face-with-hearts":{"a":"Smiling Face with Hearts","b":"1F970","j":["adore","crush","hearts","in love","face","love","like","affection","valentines","infatuation"]},"smiling-face-with-hearteyes":{"a":"Smiling Face with Heart-Eyes","b":"1F60D","j":["eye","face","love","smile","smiling face with heart-eyes","smiling_face_with_heart_eyes","like","affection","valentines","infatuation","crush","heart"]},"starstruck":{"a":"Star-Struck","b":"1F929","j":["eyes","face","grinning","star","star-struck","starry-eyed","star_struck","smile","starry"]},"face-blowing-a-kiss":{"a":"Face Blowing a Kiss","b":"1F618","j":["face","kiss","love","like","affection","valentines","infatuation"]},"kissing-face":{"a":"Kissing Face","b":"1F617","j":["face","kiss","love","like","3","valentines","infatuation"]},"smiling-face":{"a":"Smiling Face","b":"263A","j":["face","outlined","relaxed","smile","blush","massage","happiness"]},"kissing-face-with-closed-eyes":{"a":"Kissing Face with Closed Eyes","b":"1F61A","j":["closed","eye","face","kiss","love","like","affection","valentines","infatuation"]},"kissing-face-with-smiling-eyes":{"a":"Kissing Face with Smiling Eyes","b":"1F619","j":["eye","face","kiss","smile","affection","valentines","infatuation"]},"smiling-face-with-tear":{"a":"Smiling Face with Tear","b":"1F972","j":["grateful","proud","relieved","smiling","tear","touched","sad","cry","pretend"]},"face-savoring-food":{"a":"Face Savoring Food","b":"1F60B","j":["delicious","face","savouring","smile","yum","happy","joy","tongue","silly","yummy","nom"]},"face-with-tongue":{"a":"Face with Tongue","b":"1F61B","j":["face","tongue","prank","childish","playful","mischievous","smile"]},"winking-face-with-tongue":{"a":"Winking Face with Tongue","b":"1F61C","j":["eye","face","joke","tongue","wink","prank","childish","playful","mischievous","smile"]},"zany-face":{"a":"Zany Face","b":"1F92A","j":["eye","goofy","large","small","face","crazy"]},"squinting-face-with-tongue":{"a":"Squinting Face with Tongue","b":"1F61D","j":["eye","face","horrible","taste","tongue","prank","playful","mischievous","smile"]},"moneymouth-face":{"a":"Money-Mouth Face","b":"1F911","j":["face","money","money-mouth face","mouth","money_mouth_face","rich","dollar"]},"smiling-face-with-open-hands":{"a":"Smiling Face with Open Hands","b":"1F917","j":["face","hug","hugging","open hands","smiling face","hugging_face","smile"]},"face-with-hand-over-mouth":{"a":"Face with Hand over Mouth","b":"1F92D","j":["whoops","shock","sudden realization","surprise","face"]},"face-with-open-eyes-and-hand-over-mouth":{"a":"⊛ Face with Open Eyes and Hand over Mouth","b":"1FAE2","j":["amazement","awe","disbelief","embarrass","scared","surprise"]},"face-with-peeking-eye":{"a":"⊛ Face with Peeking Eye","b":"1FAE3","j":["captivated","peep","stare"]},"shushing-face":{"a":"Shushing Face","b":"1F92B","j":["quiet","shush","face","shhh"]},"thinking-face":{"a":"Thinking Face","b":"1F914","j":["face","thinking","hmmm","think","consider"]},"saluting-face":{"a":"⊛ Saluting Face","b":"1FAE1","j":["ok","salute","sunny","troops","yes"]},"zippermouth-face":{"a":"Zipper-Mouth Face","b":"1F910","j":["face","mouth","zipper","zipper-mouth face","zipper_mouth_face","sealed","secret"]},"face-with-raised-eyebrow":{"a":"Face with Raised Eyebrow","b":"1F928","j":["distrust","skeptic","disapproval","disbelief","mild surprise","scepticism","face","surprise"]},"neutral-face":{"a":"Neutral Face","b":"1F610","j":["deadpan","face","meh","neutral","indifference",":|"]},"expressionless-face":{"a":"Expressionless Face","b":"1F611","j":["expressionless","face","inexpressive","meh","unexpressive","indifferent","-_-","deadpan"]},"face-without-mouth":{"a":"Face Without Mouth","b":"1F636","j":["face","mouth","quiet","silent","hellokitty"]},"dotted-line-face":{"a":"⊛ Dotted Line Face","b":"1FAE5","j":["depressed","disappear","hide","introvert","invisible"]},"face-in-clouds":{"a":"Face in Clouds","b":"1F636-200D-1F32B-FE0F","j":["absentminded","face in clouds","face in the fog","head in clouds"]},"smirking-face":{"a":"Smirking Face","b":"1F60F","j":["face","smirk","smile","mean","prank","smug","sarcasm"]},"unamused-face":{"a":"Unamused Face","b":"1F612","j":["face","unamused","unhappy","indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"]},"face-with-rolling-eyes":{"a":"Face with Rolling Eyes","b":"1F644","j":["eyeroll","eyes","face","rolling","frustrated"]},"grimacing-face":{"a":"Grimacing Face","b":"1F62C","j":["face","grimace","teeth"]},"face-exhaling":{"a":"Face Exhaling","b":"1F62E-200D-1F4A8","j":["exhale","face exhaling","gasp","groan","relief","whisper","whistle"]},"lying-face":{"a":"Lying Face","b":"1F925","j":["face","lie","pinocchio"]},"relieved-face":{"a":"Relieved Face","b":"1F60C","j":["face","relieved","relaxed","phew","massage","happiness"]},"pensive-face":{"a":"Pensive Face","b":"1F614","j":["dejected","face","pensive","sad","depressed","upset"]},"sleepy-face":{"a":"Sleepy Face","b":"1F62A","j":["face","sleep","tired","rest","nap"]},"drooling-face":{"a":"Drooling Face","b":"1F924","j":["drooling","face"]},"sleeping-face":{"a":"Sleeping Face","b":"1F634","j":["face","sleep","zzz","tired","sleepy","night"]},"face-with-medical-mask":{"a":"Face with Medical Mask","b":"1F637","j":["cold","doctor","face","mask","sick","ill","disease"]},"face-with-thermometer":{"a":"Face with Thermometer","b":"1F912","j":["face","ill","sick","thermometer","temperature","cold","fever"]},"face-with-headbandage":{"a":"Face with Head-Bandage","b":"1F915","j":["bandage","face","face with head-bandage","hurt","injury","face_with_head_bandage","injured","clumsy"]},"nauseated-face":{"a":"Nauseated Face","b":"1F922","j":["face","nauseated","vomit","gross","green","sick","throw up","ill"]},"face-vomiting":{"a":"Face Vomiting","b":"1F92E","j":["puke","sick","vomit","face"]},"sneezing-face":{"a":"Sneezing Face","b":"1F927","j":["face","gesundheit","sneeze","sick","allergy"]},"hot-face":{"a":"Hot Face","b":"1F975","j":["feverish","heat stroke","hot","red-faced","sweating","face","heat","red"]},"cold-face":{"a":"Cold Face","b":"1F976","j":["blue-faced","cold","freezing","frostbite","icicles","face","blue","frozen"]},"woozy-face":{"a":"Woozy Face","b":"1F974","j":["dizzy","intoxicated","tipsy","uneven eyes","wavy mouth","face","wavy"]},"face-with-crossedout-eyes":{"a":"Face with Crossed-out Eyes","b":"1F635","j":["crossed-out eyes","dead","face","face with crossed-out eyes","knocked out","dizzy_face","spent","unconscious","xox","dizzy"]},"face-with-spiral-eyes":{"a":"Face with Spiral Eyes","b":"1F635-200D-1F4AB","j":["dizzy","face with spiral eyes","hypnotized","spiral","trouble","whoa"]},"exploding-head":{"a":"Exploding Head","b":"1F92F","j":["mind blown","shocked","face","mind","blown"]},"cowboy-hat-face":{"a":"Cowboy Hat Face","b":"1F920","j":["cowboy","cowgirl","face","hat"]},"partying-face":{"a":"Partying Face","b":"1F973","j":["celebration","hat","horn","party","face","woohoo"]},"disguised-face":{"a":"Disguised Face","b":"1F978","j":["disguise","face","glasses","incognito","nose","pretent","brows","moustache"]},"smiling-face-with-sunglasses":{"a":"Smiling Face with Sunglasses","b":"1F60E","j":["bright","cool","face","sun","sunglasses","smile","summer","beach","sunglass"]},"nerd-face":{"a":"Nerd Face","b":"1F913","j":["face","geek","nerd","nerdy","dork"]},"face-with-monocle":{"a":"Face with Monocle","b":"1F9D0","j":["stuffy","wealthy","face"]},"confused-face":{"a":"Confused Face","b":"1F615","j":["confused","face","meh","indifference","huh","weird","hmmm",":/"]},"face-with-diagonal-mouth":{"a":"⊛ Face with Diagonal Mouth","b":"1FAE4","j":["disappointed","meh","skeptical","unsure"]},"worried-face":{"a":"Worried Face","b":"1F61F","j":["face","worried","concern","nervous",":("]},"slightly-frowning-face":{"a":"Slightly Frowning Face","b":"1F641","j":["face","frown","frowning","disappointed","sad","upset"]},"frowning-face":{"a":"Frowning Face","b":"2639","j":["face","frown","sad","upset"]},"face-with-open-mouth":{"a":"Face with Open Mouth","b":"1F62E","j":["face","mouth","open","sympathy","surprise","impressed","wow","whoa",":O"]},"hushed-face":{"a":"Hushed Face","b":"1F62F","j":["face","hushed","stunned","surprised","woo","shh"]},"astonished-face":{"a":"Astonished Face","b":"1F632","j":["astonished","face","shocked","totally","xox","surprised","poisoned"]},"flushed-face":{"a":"Flushed Face","b":"1F633","j":["dazed","face","flushed","blush","shy","flattered"]},"pleading-face":{"a":"Pleading Face","b":"1F97A","j":["begging","mercy","puppy eyes","face"]},"face-holding-back-tears":{"a":"⊛ Face Holding Back Tears","b":"1F979","j":["angry","cry","proud","resist","sad"]},"frowning-face-with-open-mouth":{"a":"Frowning Face with Open Mouth","b":"1F626","j":["face","frown","mouth","open","aw","what"]},"anguished-face":{"a":"Anguished Face","b":"1F627","j":["anguished","face","stunned","nervous"]},"fearful-face":{"a":"Fearful Face","b":"1F628","j":["face","fear","fearful","scared","terrified","nervous","oops","huh"]},"anxious-face-with-sweat":{"a":"Anxious Face with Sweat","b":"1F630","j":["blue","cold","face","rushed","sweat","nervous"]},"sad-but-relieved-face":{"a":"Sad but Relieved Face","b":"1F625","j":["disappointed","face","relieved","whew","phew","sweat","nervous"]},"crying-face":{"a":"Crying Face","b":"1F622","j":["cry","face","sad","tear","tears","depressed","upset",":'("]},"loudly-crying-face":{"a":"Loudly Crying Face","b":"1F62D","j":["cry","face","sad","sob","tear","tears","upset","depressed"]},"face-screaming-in-fear":{"a":"Face Screaming in Fear","b":"1F631","j":["face","fear","munch","scared","scream","omg"]},"confounded-face":{"a":"Confounded Face","b":"1F616","j":["confounded","face","confused","sick","unwell","oops",":S"]},"persevering-face":{"a":"Persevering Face","b":"1F623","j":["face","persevere","sick","no","upset","oops"]},"disappointed-face":{"a":"Disappointed Face","b":"1F61E","j":["disappointed","face","sad","upset","depressed",":("]},"downcast-face-with-sweat":{"a":"Downcast Face with Sweat","b":"1F613","j":["cold","face","sweat","hot","sad","tired","exercise"]},"weary-face":{"a":"Weary Face","b":"1F629","j":["face","tired","weary","sleepy","sad","frustrated","upset"]},"tired-face":{"a":"Tired Face","b":"1F62B","j":["face","tired","sick","whine","upset","frustrated"]},"yawning-face":{"a":"Yawning Face","b":"1F971","j":["bored","tired","yawn","sleepy"]},"face-with-steam-from-nose":{"a":"Face with Steam From Nose","b":"1F624","j":["face","triumph","won","gas","phew","proud","pride"]},"pouting-face":{"a":"Pouting Face","b":"1F621","j":["angry","face","mad","pouting","rage","red","hate","despise"]},"angry-face":{"a":"Angry Face","b":"1F620","j":["anger","angry","face","mad","annoyed","frustrated"]},"face-with-symbols-on-mouth":{"a":"Face with Symbols on Mouth","b":"1F92C","j":["swearing","cursing","face","cussing","profanity","expletive"]},"smiling-face-with-horns":{"a":"Smiling Face with Horns","b":"1F608","j":["face","fairy tale","fantasy","horns","smile","devil"]},"angry-face-with-horns":{"a":"Angry Face with Horns","b":"1F47F","j":["demon","devil","face","fantasy","imp","angry","horns"]},"skull":{"a":"Skull","b":"1F480","j":["death","face","fairy tale","monster","dead","skeleton","creepy"]},"skull-and-crossbones":{"a":"Skull and Crossbones","b":"2620","j":["crossbones","death","face","monster","skull","poison","danger","deadly","scary","pirate","evil"]},"pile-of-poo":{"a":"Pile of Poo","b":"1F4A9","j":["dung","face","monster","poo","poop","hankey","shitface","fail","turd","shit"]},"clown-face":{"a":"Clown Face","b":"1F921","j":["clown","face"]},"ogre":{"a":"Ogre","b":"1F479","j":["creature","face","fairy tale","fantasy","monster","troll","red","mask","halloween","scary","creepy","devil","demon","japanese"]},"goblin":{"a":"Goblin","b":"1F47A","j":["creature","face","fairy tale","fantasy","monster","red","evil","mask","scary","creepy","japanese"]},"ghost":{"a":"Ghost","b":"1F47B","j":["creature","face","fairy tale","fantasy","monster","halloween","spooky","scary"]},"alien":{"a":"Alien","b":"1F47D","j":["creature","extraterrestrial","face","fantasy","ufo","UFO","paul","weird","outer_space"]},"alien-monster":{"a":"Alien Monster","b":"1F47E","j":["alien","creature","extraterrestrial","face","monster","ufo","game","arcade","play"]},"robot":{"a":"Robot","b":"1F916","j":["face","monster","computer","machine","bot"]},"grinning-cat":{"a":"Grinning Cat","b":"1F63A","j":["cat","face","grinning","mouth","open","smile","animal","cats","happy"]},"grinning-cat-with-smiling-eyes":{"a":"Grinning Cat with Smiling Eyes","b":"1F638","j":["cat","eye","face","grin","smile","animal","cats"]},"cat-with-tears-of-joy":{"a":"Cat with Tears of Joy","b":"1F639","j":["cat","face","joy","tear","animal","cats","haha","happy","tears"]},"smiling-cat-with-hearteyes":{"a":"Smiling Cat with Heart-Eyes","b":"1F63B","j":["cat","eye","face","heart","love","smile","smiling cat with heart-eyes","smiling_cat_with_heart_eyes","animal","like","affection","cats","valentines"]},"cat-with-wry-smile":{"a":"Cat with Wry Smile","b":"1F63C","j":["cat","face","ironic","smile","wry","animal","cats","smirk"]},"kissing-cat":{"a":"Kissing Cat","b":"1F63D","j":["cat","eye","face","kiss","animal","cats"]},"weary-cat":{"a":"Weary Cat","b":"1F640","j":["cat","face","oh","surprised","weary","animal","cats","munch","scared","scream"]},"crying-cat":{"a":"Crying Cat","b":"1F63F","j":["cat","cry","face","sad","tear","animal","tears","weep","cats","upset"]},"pouting-cat":{"a":"Pouting Cat","b":"1F63E","j":["cat","face","pouting","animal","cats"]},"seenoevil-monkey":{"a":"See-No-Evil Monkey","b":"1F648","j":["evil","face","forbidden","monkey","see","see-no-evil monkey","see_no_evil_monkey","animal","nature","haha"]},"hearnoevil-monkey":{"a":"Hear-No-Evil Monkey","b":"1F649","j":["evil","face","forbidden","hear","hear-no-evil monkey","monkey","hear_no_evil_monkey","animal","nature"]},"speaknoevil-monkey":{"a":"Speak-No-Evil Monkey","b":"1F64A","j":["evil","face","forbidden","monkey","speak","speak-no-evil monkey","speak_no_evil_monkey","animal","nature","omg"]},"kiss-mark":{"a":"Kiss Mark","b":"1F48B","j":["kiss","lips","face","love","like","affection","valentines"]},"love-letter":{"a":"Love Letter","b":"1F48C","j":["heart","letter","love","mail","email","like","affection","envelope","valentines"]},"heart-with-arrow":{"a":"Heart with Arrow","b":"1F498","j":["arrow","cupid","love","like","heart","affection","valentines"]},"heart-with-ribbon":{"a":"Heart with Ribbon","b":"1F49D","j":["ribbon","valentine","love","valentines"]},"sparkling-heart":{"a":"Sparkling Heart","b":"1F496","j":["excited","sparkle","love","like","affection","valentines"]},"growing-heart":{"a":"Growing Heart","b":"1F497","j":["excited","growing","nervous","pulse","like","love","affection","valentines","pink"]},"beating-heart":{"a":"Beating Heart","b":"1F493","j":["beating","heartbeat","pulsating","love","like","affection","valentines","pink","heart"]},"revolving-hearts":{"a":"Revolving Hearts","b":"1F49E","j":["revolving","love","like","affection","valentines"]},"two-hearts":{"a":"Two Hearts","b":"1F495","j":["love","like","affection","valentines","heart"]},"heart-decoration":{"a":"Heart Decoration","b":"1F49F","j":["heart","purple-square","love","like"]},"heart-exclamation":{"a":"Heart Exclamation","b":"2763","j":["exclamation","mark","punctuation","decoration","love"]},"broken-heart":{"a":"Broken Heart","b":"1F494","j":["break","broken","sad","sorry","heart","heartbreak"]},"heart-on-fire":{"a":"Heart on Fire","b":"2764-FE0F-200D-1F525","j":["burn","heart","heart on fire","love","lust","sacred heart"]},"mending-heart":{"a":"Mending Heart","b":"2764-FE0F-200D-1FA79","j":["healthier","improving","mending","mending heart","recovering","recuperating","well"]},"red-heart":{"a":"Red Heart","b":"2764","j":["heart","love","like","valentines"]},"orange-heart":{"a":"Orange Heart","b":"1F9E1","j":["orange","love","like","affection","valentines"]},"yellow-heart":{"a":"Yellow Heart","b":"1F49B","j":["yellow","love","like","affection","valentines"]},"green-heart":{"a":"Green Heart","b":"1F49A","j":["green","love","like","affection","valentines"]},"blue-heart":{"a":"Blue Heart","b":"1F499","j":["blue","love","like","affection","valentines"]},"purple-heart":{"a":"Purple Heart","b":"1F49C","j":["purple","love","like","affection","valentines"]},"brown-heart":{"a":"Brown Heart","b":"1F90E","j":["brown","heart","coffee"]},"black-heart":{"a":"Black Heart","b":"1F5A4","j":["black","evil","wicked"]},"white-heart":{"a":"White Heart","b":"1F90D","j":["heart","white","pure"]},"hundred-points":{"a":"Hundred Points","b":"1F4AF","j":["100","full","hundred","score","perfect","numbers","century","exam","quiz","test","pass"]},"anger-symbol":{"a":"Anger Symbol","b":"1F4A2","j":["angry","comic","mad"]},"collision":{"a":"Collision","b":"1F4A5","j":["boom","comic","bomb","explode","explosion","blown"]},"dizzy":{"a":"Dizzy","b":"1F4AB","j":["comic","star","sparkle","shoot","magic"]},"sweat-droplets":{"a":"Sweat Droplets","b":"1F4A6","j":["comic","splashing","sweat","water","drip","oops"]},"dashing-away":{"a":"Dashing Away","b":"1F4A8","j":["comic","dash","running","wind","air","fast","shoo","fart","smoke","puff"]},"hole":{"a":"Hole","b":"1F573","j":["embarrassing"]},"bomb":{"a":"Bomb","b":"1F4A3","j":["comic","boom","explode","explosion","terrorism"]},"speech-balloon":{"a":"Speech Balloon","b":"1F4AC","j":["balloon","bubble","comic","dialog","speech","words","message","talk","chatting"]},"eye-in-speech-bubble":{"a":"Eye in Speech Bubble","b":"1F441-FE0F-200D-1F5E8-FE0F","j":["eye","speech bubble","witness","info"]},"left-speech-bubble":{"a":"Left Speech Bubble","b":"1F5E8","j":["dialog","speech","words","message","talk","chatting"]},"right-anger-bubble":{"a":"Right Anger Bubble","b":"1F5EF","j":["angry","balloon","bubble","mad","caption","speech","thinking"]},"thought-balloon":{"a":"Thought Balloon","b":"1F4AD","j":["balloon","bubble","comic","thought","cloud","speech","thinking","dream"]},"zzz":{"a":"Zzz","b":"1F4A4","j":["comic","sleep","sleepy","tired","dream"]},"waving-hand":{"a":"Waving Hand","b":"1F44B","j":["hand","wave","waving","hands","gesture","goodbye","solong","farewell","hello","hi","palm"]},"raised-back-of-hand":{"a":"Raised Back of Hand","b":"1F91A","j":["backhand","raised","fingers"]},"hand-with-fingers-splayed":{"a":"Hand with Fingers Splayed","b":"1F590","j":["finger","hand","splayed","fingers","palm"]},"raised-hand":{"a":"Raised Hand","b":"270B","j":["hand","high 5","high five","fingers","stop","highfive","palm","ban"]},"vulcan-salute":{"a":"Vulcan Salute","b":"1F596","j":["finger","hand","spock","vulcan","fingers","star trek"]},"rightwards-hand":{"a":"⊛ Rightwards Hand","b":"1FAF1","j":["hand","right","rightward"]},"leftwards-hand":{"a":"⊛ Leftwards Hand","b":"1FAF2","j":["hand","left","leftward"]},"palm-down-hand":{"a":"⊛ Palm Down Hand","b":"1FAF3","j":["dismiss","drop","shoo"]},"palm-up-hand":{"a":"⊛ Palm Up Hand","b":"1FAF4","j":["beckon","catch","come","offer"]},"ok-hand":{"a":"Ok Hand","b":"1F44C","j":["hand","OK","fingers","limbs","perfect","ok","okay"]},"pinched-fingers":{"a":"Pinched Fingers","b":"1F90C","j":["fingers","hand gesture","interrogation","pinched","sarcastic","size","tiny","small"]},"pinching-hand":{"a":"Pinching Hand","b":"1F90F","j":["small amount","tiny","small","size"]},"victory-hand":{"a":"Victory Hand","b":"270C","j":["hand","v","victory","fingers","ohyeah","peace","two"]},"crossed-fingers":{"a":"Crossed Fingers","b":"1F91E","j":["cross","finger","hand","luck","good","lucky"]},"hand-with-index-finger-and-thumb-crossed":{"a":"⊛ Hand with Index Finger and Thumb Crossed","b":"1FAF0","j":["expensive","heart","love","money","snap"]},"loveyou-gesture":{"a":"Love-You Gesture","b":"1F91F","j":["hand","ILY","love-you gesture","love_you_gesture","fingers","gesture"]},"sign-of-the-horns":{"a":"Sign of the Horns","b":"1F918","j":["finger","hand","horns","rock-on","fingers","evil_eye","sign_of_horns","rock_on"]},"call-me-hand":{"a":"Call Me Hand","b":"1F919","j":["call","hand","hands","gesture","shaka"]},"backhand-index-pointing-left":{"a":"Backhand Index Pointing Left","b":"1F448","j":["backhand","finger","hand","index","point","direction","fingers","left"]},"backhand-index-pointing-right":{"a":"Backhand Index Pointing Right","b":"1F449","j":["backhand","finger","hand","index","point","fingers","direction","right"]},"backhand-index-pointing-up":{"a":"Backhand Index Pointing Up","b":"1F446","j":["backhand","finger","hand","point","up","fingers","direction"]},"middle-finger":{"a":"Middle Finger","b":"1F595","j":["finger","hand","fingers","rude","middle","flipping"]},"backhand-index-pointing-down":{"a":"Backhand Index Pointing Down","b":"1F447","j":["backhand","down","finger","hand","point","fingers","direction"]},"index-pointing-up":{"a":"Index Pointing Up","b":"261D","j":["finger","hand","index","point","up","fingers","direction"]},"index-pointing-at-the-viewer":{"a":"⊛ Index Pointing at the Viewer","b":"1FAF5","j":["point","you"]},"thumbs-up":{"a":"Thumbs Up","b":"1F44D","j":["+1","hand","thumb","up","thumbsup","yes","awesome","good","agree","accept","cool","like"]},"thumbs-down":{"a":"Thumbs Down","b":"1F44E","j":["-1","down","hand","thumb","thumbsdown","no","dislike"]},"raised-fist":{"a":"Raised Fist","b":"270A","j":["clenched","fist","hand","punch","fingers","grasp"]},"oncoming-fist":{"a":"Oncoming Fist","b":"1F44A","j":["clenched","fist","hand","punch","angry","violence","hit","attack"]},"leftfacing-fist":{"a":"Left-Facing Fist","b":"1F91B","j":["fist","left-facing fist","leftwards","left_facing_fist","hand","fistbump"]},"rightfacing-fist":{"a":"Right-Facing Fist","b":"1F91C","j":["fist","right-facing fist","rightwards","right_facing_fist","hand","fistbump"]},"clapping-hands":{"a":"Clapping Hands","b":"1F44F","j":["clap","hand","hands","praise","applause","congrats","yay"]},"raising-hands":{"a":"Raising Hands","b":"1F64C","j":["celebration","gesture","hand","hooray","raised","yea","hands"]},"heart-hands":{"a":"⊛ Heart Hands","b":"1FAF6","j":["love"]},"open-hands":{"a":"Open Hands","b":"1F450","j":["hand","open","fingers","butterfly","hands"]},"palms-up-together":{"a":"Palms Up Together","b":"1F932","j":["prayer","cupped hands","hands","gesture","cupped"]},"handshake":{"a":"Handshake","b":"1F91D","j":["agreement","hand","meeting","shake"]},"folded-hands":{"a":"Folded Hands","b":"1F64F","j":["ask","hand","high 5","high five","please","pray","thanks","hope","wish","namaste","highfive"]},"writing-hand":{"a":"Writing Hand","b":"270D","j":["hand","write","lower_left_ballpoint_pen","stationery","compose"]},"nail-polish":{"a":"Nail Polish","b":"1F485","j":["care","cosmetics","manicure","nail","polish","beauty","finger","fashion"]},"selfie":{"a":"Selfie","b":"1F933","j":["camera","phone"]},"flexed-biceps":{"a":"Flexed Biceps","b":"1F4AA","j":["biceps","comic","flex","muscle","arm","hand","summer","strong"]},"mechanical-arm":{"a":"Mechanical Arm","b":"1F9BE","j":["accessibility","prosthetic"]},"mechanical-leg":{"a":"Mechanical Leg","b":"1F9BF","j":["accessibility","prosthetic"]},"leg":{"a":"Leg","b":"1F9B5","j":["kick","limb"]},"foot":{"a":"Foot","b":"1F9B6","j":["kick","stomp"]},"ear":{"a":"Ear","b":"1F442","j":["body","face","hear","sound","listen"]},"ear-with-hearing-aid":{"a":"Ear with Hearing Aid","b":"1F9BB","j":["accessibility","hard of hearing"]},"nose":{"a":"Nose","b":"1F443","j":["body","smell","sniff"]},"brain":{"a":"Brain","b":"1F9E0","j":["intelligent","smart"]},"anatomical-heart":{"a":"Anatomical Heart","b":"1FAC0","j":["anatomical","cardiology","heart","organ","pulse","health","heartbeat"]},"lungs":{"a":"Lungs","b":"1FAC1","j":["breath","exhalation","inhalation","organ","respiration","breathe"]},"tooth":{"a":"Tooth","b":"1F9B7","j":["dentist","teeth"]},"bone":{"a":"Bone","b":"1F9B4","j":["skeleton"]},"eyes":{"a":"Eyes","b":"1F440","j":["eye","face","look","watch","stalk","peek","see"]},"eye":{"a":"Eye","b":"1F441","j":["body","face","look","see","watch","stare"]},"tongue":{"a":"Tongue","b":"1F445","j":["body","mouth","playful"]},"mouth":{"a":"Mouth","b":"1F444","j":["lips","kiss"]},"biting-lip":{"a":"⊛ Biting Lip","b":"1FAE6","j":["anxious","fear","flirting","nervous","uncomfortable","worried"]},"baby":{"a":"Baby","b":"1F476","j":["young","child","boy","girl","toddler"]},"child":{"a":"Child","b":"1F9D2","j":["gender-neutral","unspecified gender","young"]},"boy":{"a":"Boy","b":"1F466","j":["young","man","male","guy","teenager"]},"girl":{"a":"Girl","b":"1F467","j":["Virgo","young","zodiac","female","woman","teenager"]},"person":{"a":"Person","b":"1F9D1","j":["adult","gender-neutral","unspecified gender"]},"person-blond-hair":{"a":"Person: Blond Hair","b":"1F471","j":["blond","blond-haired person","hair","person: blond hair","hairstyle"]},"man":{"a":"Man","b":"1F468","j":["adult","mustache","father","dad","guy","classy","sir","moustache"]},"person-beard":{"a":"Person: Beard","b":"1F9D4","j":["beard","person","person: beard","bewhiskered","man_beard"]},"man-beard":{"a":"Man: Beard","b":"1F9D4-200D-2642-FE0F","j":["beard","man","man: beard"]},"woman-beard":{"a":"Woman: Beard","b":"1F9D4-200D-2640-FE0F","j":["beard","woman","woman: beard"]},"man-red-hair":{"a":"Man: Red Hair","b":"1F468-200D-1F9B0","j":["adult","man","red hair","hairstyle"]},"man-curly-hair":{"a":"Man: Curly Hair","b":"1F468-200D-1F9B1","j":["adult","curly hair","man","hairstyle"]},"man-white-hair":{"a":"Man: White Hair","b":"1F468-200D-1F9B3","j":["adult","man","white hair","old","elder"]},"man-bald":{"a":"Man: Bald","b":"1F468-200D-1F9B2","j":["adult","bald","man","hairless"]},"woman":{"a":"Woman","b":"1F469","j":["adult","female","girls","lady"]},"woman-red-hair":{"a":"Woman: Red Hair","b":"1F469-200D-1F9B0","j":["adult","red hair","woman","hairstyle"]},"person-red-hair":{"a":"Person: Red Hair","b":"1F9D1-200D-1F9B0","j":["adult","gender-neutral","person","red hair","unspecified gender","hairstyle"]},"woman-curly-hair":{"a":"Woman: Curly Hair","b":"1F469-200D-1F9B1","j":["adult","curly hair","woman","hairstyle"]},"person-curly-hair":{"a":"Person: Curly Hair","b":"1F9D1-200D-1F9B1","j":["adult","curly hair","gender-neutral","person","unspecified gender","hairstyle"]},"woman-white-hair":{"a":"Woman: White Hair","b":"1F469-200D-1F9B3","j":["adult","white hair","woman","old","elder"]},"person-white-hair":{"a":"Person: White Hair","b":"1F9D1-200D-1F9B3","j":["adult","gender-neutral","person","unspecified gender","white hair","elder","old"]},"woman-bald":{"a":"Woman: Bald","b":"1F469-200D-1F9B2","j":["adult","bald","woman","hairless"]},"person-bald":{"a":"Person: Bald","b":"1F9D1-200D-1F9B2","j":["adult","bald","gender-neutral","person","unspecified gender","hairless"]},"woman-blond-hair":{"a":"Woman: Blond Hair","b":"1F471-200D-2640-FE0F","j":["blond-haired woman","blonde","hair","woman","woman: blond hair","female","girl","person"]},"man-blond-hair":{"a":"Man: Blond Hair","b":"1F471-200D-2642-FE0F","j":["blond","blond-haired man","hair","man","man: blond hair","male","boy","blonde","guy","person"]},"older-person":{"a":"Older Person","b":"1F9D3","j":["adult","gender-neutral","old","unspecified gender","human","elder","senior"]},"old-man":{"a":"Old Man","b":"1F474","j":["adult","man","old","human","male","men","elder","senior"]},"old-woman":{"a":"Old Woman","b":"1F475","j":["adult","old","woman","human","female","women","lady","elder","senior"]},"person-frowning":{"a":"Person Frowning","b":"1F64D","j":["frown","gesture","worried"]},"man-frowning":{"a":"Man Frowning","b":"1F64D-200D-2642-FE0F","j":["frowning","gesture","man","male","boy","sad","depressed","discouraged","unhappy"]},"woman-frowning":{"a":"Woman Frowning","b":"1F64D-200D-2640-FE0F","j":["frowning","gesture","woman","female","girl","sad","depressed","discouraged","unhappy"]},"person-pouting":{"a":"Person Pouting","b":"1F64E","j":["gesture","pouting","upset"]},"man-pouting":{"a":"Man Pouting","b":"1F64E-200D-2642-FE0F","j":["gesture","man","pouting","male","boy"]},"woman-pouting":{"a":"Woman Pouting","b":"1F64E-200D-2640-FE0F","j":["gesture","pouting","woman","female","girl"]},"person-gesturing-no":{"a":"Person Gesturing No","b":"1F645","j":["forbidden","gesture","hand","person gesturing NO","prohibited","decline"]},"man-gesturing-no":{"a":"Man Gesturing No","b":"1F645-200D-2642-FE0F","j":["forbidden","gesture","hand","man","man gesturing NO","prohibited","male","boy","nope"]},"woman-gesturing-no":{"a":"Woman Gesturing No","b":"1F645-200D-2640-FE0F","j":["forbidden","gesture","hand","prohibited","woman","woman gesturing NO","female","girl","nope"]},"person-gesturing-ok":{"a":"Person Gesturing Ok","b":"1F646","j":["gesture","hand","OK","person gesturing OK","agree"]},"man-gesturing-ok":{"a":"Man Gesturing Ok","b":"1F646-200D-2642-FE0F","j":["gesture","hand","man","man gesturing OK","OK","men","boy","male","blue","human"]},"woman-gesturing-ok":{"a":"Woman Gesturing Ok","b":"1F646-200D-2640-FE0F","j":["gesture","hand","OK","woman","woman gesturing OK","women","girl","female","pink","human"]},"person-tipping-hand":{"a":"Person Tipping Hand","b":"1F481","j":["hand","help","information","sassy","tipping"]},"man-tipping-hand":{"a":"Man Tipping Hand","b":"1F481-200D-2642-FE0F","j":["man","sassy","tipping hand","male","boy","human","information"]},"woman-tipping-hand":{"a":"Woman Tipping Hand","b":"1F481-200D-2640-FE0F","j":["sassy","tipping hand","woman","female","girl","human","information"]},"person-raising-hand":{"a":"Person Raising Hand","b":"1F64B","j":["gesture","hand","happy","raised","question"]},"man-raising-hand":{"a":"Man Raising Hand","b":"1F64B-200D-2642-FE0F","j":["gesture","man","raising hand","male","boy"]},"woman-raising-hand":{"a":"Woman Raising Hand","b":"1F64B-200D-2640-FE0F","j":["gesture","raising hand","woman","female","girl"]},"deaf-person":{"a":"Deaf Person","b":"1F9CF","j":["accessibility","deaf","ear","hear"]},"deaf-man":{"a":"Deaf Man","b":"1F9CF-200D-2642-FE0F","j":["deaf","man","accessibility"]},"deaf-woman":{"a":"Deaf Woman","b":"1F9CF-200D-2640-FE0F","j":["deaf","woman","accessibility"]},"person-bowing":{"a":"Person Bowing","b":"1F647","j":["apology","bow","gesture","sorry","respectiful"]},"man-bowing":{"a":"Man Bowing","b":"1F647-200D-2642-FE0F","j":["apology","bowing","favor","gesture","man","sorry","male","boy"]},"woman-bowing":{"a":"Woman Bowing","b":"1F647-200D-2640-FE0F","j":["apology","bowing","favor","gesture","sorry","woman","female","girl"]},"person-facepalming":{"a":"Person Facepalming","b":"1F926","j":["disbelief","exasperation","face","palm","disappointed"]},"man-facepalming":{"a":"Man Facepalming","b":"1F926-200D-2642-FE0F","j":["disbelief","exasperation","facepalm","man","male","boy"]},"woman-facepalming":{"a":"Woman Facepalming","b":"1F926-200D-2640-FE0F","j":["disbelief","exasperation","facepalm","woman","female","girl"]},"person-shrugging":{"a":"Person Shrugging","b":"1F937","j":["doubt","ignorance","indifference","shrug","regardless"]},"man-shrugging":{"a":"Man Shrugging","b":"1F937-200D-2642-FE0F","j":["doubt","ignorance","indifference","man","shrug","male","boy","confused","indifferent"]},"woman-shrugging":{"a":"Woman Shrugging","b":"1F937-200D-2640-FE0F","j":["doubt","ignorance","indifference","shrug","woman","female","girl","confused","indifferent"]},"health-worker":{"a":"Health Worker","b":"1F9D1-200D-2695-FE0F","j":["doctor","healthcare","nurse","therapist","hospital"]},"man-health-worker":{"a":"Man Health Worker","b":"1F468-200D-2695-FE0F","j":["doctor","healthcare","man","nurse","therapist","human"]},"woman-health-worker":{"a":"Woman Health Worker","b":"1F469-200D-2695-FE0F","j":["doctor","healthcare","nurse","therapist","woman","human"]},"student":{"a":"Student","b":"1F9D1-200D-1F393","j":["graduate","learn"]},"man-student":{"a":"Man Student","b":"1F468-200D-1F393","j":["graduate","man","student","human"]},"woman-student":{"a":"Woman Student","b":"1F469-200D-1F393","j":["graduate","student","woman","human"]},"teacher":{"a":"Teacher","b":"1F9D1-200D-1F3EB","j":["instructor","professor"]},"man-teacher":{"a":"Man Teacher","b":"1F468-200D-1F3EB","j":["instructor","man","professor","teacher","human"]},"woman-teacher":{"a":"Woman Teacher","b":"1F469-200D-1F3EB","j":["instructor","professor","teacher","woman","human"]},"judge":{"a":"Judge","b":"1F9D1-200D-2696-FE0F","j":["justice","scales","law"]},"man-judge":{"a":"Man Judge","b":"1F468-200D-2696-FE0F","j":["judge","justice","man","scales","court","human"]},"woman-judge":{"a":"Woman Judge","b":"1F469-200D-2696-FE0F","j":["judge","justice","scales","woman","court","human"]},"farmer":{"a":"Farmer","b":"1F9D1-200D-1F33E","j":["gardener","rancher","crops"]},"man-farmer":{"a":"Man Farmer","b":"1F468-200D-1F33E","j":["farmer","gardener","man","rancher","human"]},"woman-farmer":{"a":"Woman Farmer","b":"1F469-200D-1F33E","j":["farmer","gardener","rancher","woman","human"]},"cook":{"a":"Cook","b":"1F9D1-200D-1F373","j":["chef","food","kitchen","culinary"]},"man-cook":{"a":"Man Cook","b":"1F468-200D-1F373","j":["chef","cook","man","human"]},"woman-cook":{"a":"Woman Cook","b":"1F469-200D-1F373","j":["chef","cook","woman","human"]},"mechanic":{"a":"Mechanic","b":"1F9D1-200D-1F527","j":["electrician","plumber","tradesperson","worker","technician"]},"man-mechanic":{"a":"Man Mechanic","b":"1F468-200D-1F527","j":["electrician","man","mechanic","plumber","tradesperson","human","wrench"]},"woman-mechanic":{"a":"Woman Mechanic","b":"1F469-200D-1F527","j":["electrician","mechanic","plumber","tradesperson","woman","human","wrench"]},"factory-worker":{"a":"Factory Worker","b":"1F9D1-200D-1F3ED","j":["assembly","factory","industrial","worker","labor"]},"man-factory-worker":{"a":"Man Factory Worker","b":"1F468-200D-1F3ED","j":["assembly","factory","industrial","man","worker","human"]},"woman-factory-worker":{"a":"Woman Factory Worker","b":"1F469-200D-1F3ED","j":["assembly","factory","industrial","woman","worker","human"]},"office-worker":{"a":"Office Worker","b":"1F9D1-200D-1F4BC","j":["architect","business","manager","white-collar"]},"man-office-worker":{"a":"Man Office Worker","b":"1F468-200D-1F4BC","j":["architect","business","man","manager","white-collar","human"]},"woman-office-worker":{"a":"Woman Office Worker","b":"1F469-200D-1F4BC","j":["architect","business","manager","white-collar","woman","human"]},"scientist":{"a":"Scientist","b":"1F9D1-200D-1F52C","j":["biologist","chemist","engineer","physicist","chemistry"]},"man-scientist":{"a":"Man Scientist","b":"1F468-200D-1F52C","j":["biologist","chemist","engineer","man","physicist","scientist","human"]},"woman-scientist":{"a":"Woman Scientist","b":"1F469-200D-1F52C","j":["biologist","chemist","engineer","physicist","scientist","woman","human"]},"technologist":{"a":"Technologist","b":"1F9D1-200D-1F4BB","j":["coder","developer","inventor","software","computer"]},"man-technologist":{"a":"Man Technologist","b":"1F468-200D-1F4BB","j":["coder","developer","inventor","man","software","technologist","engineer","programmer","human","laptop","computer"]},"woman-technologist":{"a":"Woman Technologist","b":"1F469-200D-1F4BB","j":["coder","developer","inventor","software","technologist","woman","engineer","programmer","human","laptop","computer"]},"singer":{"a":"Singer","b":"1F9D1-200D-1F3A4","j":["actor","entertainer","rock","star","song","artist","performer"]},"man-singer":{"a":"Man Singer","b":"1F468-200D-1F3A4","j":["actor","entertainer","man","rock","singer","star","rockstar","human"]},"woman-singer":{"a":"Woman Singer","b":"1F469-200D-1F3A4","j":["actor","entertainer","rock","singer","star","woman","rockstar","human"]},"artist":{"a":"Artist","b":"1F9D1-200D-1F3A8","j":["palette","painting","draw","creativity"]},"man-artist":{"a":"Man Artist","b":"1F468-200D-1F3A8","j":["artist","man","palette","painter","human"]},"woman-artist":{"a":"Woman Artist","b":"1F469-200D-1F3A8","j":["artist","palette","woman","painter","human"]},"pilot":{"a":"Pilot","b":"1F9D1-200D-2708-FE0F","j":["plane","fly","airplane"]},"man-pilot":{"a":"Man Pilot","b":"1F468-200D-2708-FE0F","j":["man","pilot","plane","aviator","human"]},"woman-pilot":{"a":"Woman Pilot","b":"1F469-200D-2708-FE0F","j":["pilot","plane","woman","aviator","human"]},"astronaut":{"a":"Astronaut","b":"1F9D1-200D-1F680","j":["rocket","outerspace"]},"man-astronaut":{"a":"Man Astronaut","b":"1F468-200D-1F680","j":["astronaut","man","rocket","space","human"]},"woman-astronaut":{"a":"Woman Astronaut","b":"1F469-200D-1F680","j":["astronaut","rocket","woman","space","human"]},"firefighter":{"a":"Firefighter","b":"1F9D1-200D-1F692","j":["firetruck","fire"]},"man-firefighter":{"a":"Man Firefighter","b":"1F468-200D-1F692","j":["firefighter","firetruck","man","fireman","human"]},"woman-firefighter":{"a":"Woman Firefighter","b":"1F469-200D-1F692","j":["firefighter","firetruck","woman","fireman","human"]},"police-officer":{"a":"Police Officer","b":"1F46E","j":["cop","officer","police"]},"man-police-officer":{"a":"Man Police Officer","b":"1F46E-200D-2642-FE0F","j":["cop","man","officer","police","law","legal","enforcement","arrest","911"]},"woman-police-officer":{"a":"Woman Police Officer","b":"1F46E-200D-2640-FE0F","j":["cop","officer","police","woman","law","legal","enforcement","arrest","911","female"]},"detective":{"a":"Detective","b":"1F575","j":["sleuth","spy","human"]},"man-detective":{"a":"Man Detective","b":"1F575-FE0F-200D-2642-FE0F","j":["detective","man","sleuth","spy","crime"]},"woman-detective":{"a":"Woman Detective","b":"1F575-FE0F-200D-2640-FE0F","j":["detective","sleuth","spy","woman","human","female"]},"guard":{"a":"Guard","b":"1F482","j":["protect"]},"man-guard":{"a":"Man Guard","b":"1F482-200D-2642-FE0F","j":["guard","man","uk","gb","british","male","guy","royal"]},"woman-guard":{"a":"Woman Guard","b":"1F482-200D-2640-FE0F","j":["guard","woman","uk","gb","british","female","royal"]},"ninja":{"a":"Ninja","b":"1F977","j":["fighter","hidden","stealth","ninjutsu","skills","japanese"]},"construction-worker":{"a":"Construction Worker","b":"1F477","j":["construction","hat","worker","labor","build"]},"man-construction-worker":{"a":"Man Construction Worker","b":"1F477-200D-2642-FE0F","j":["construction","man","worker","male","human","wip","guy","build","labor"]},"woman-construction-worker":{"a":"Woman Construction Worker","b":"1F477-200D-2640-FE0F","j":["construction","woman","worker","female","human","wip","build","labor"]},"person-with-crown":{"a":"⊛ Person with Crown","b":"1FAC5","j":["monarch","noble","regal","royalty"]},"prince":{"a":"Prince","b":"1F934","j":["boy","man","male","crown","royal","king"]},"princess":{"a":"Princess","b":"1F478","j":["fairy tale","fantasy","girl","woman","female","blond","crown","royal","queen"]},"person-wearing-turban":{"a":"Person Wearing Turban","b":"1F473","j":["turban","headdress"]},"man-wearing-turban":{"a":"Man Wearing Turban","b":"1F473-200D-2642-FE0F","j":["man","turban","male","indian","hinduism","arabs"]},"woman-wearing-turban":{"a":"Woman Wearing Turban","b":"1F473-200D-2640-FE0F","j":["turban","woman","female","indian","hinduism","arabs"]},"person-with-skullcap":{"a":"Person with Skullcap","b":"1F472","j":["cap","gua pi mao","hat","person","skullcap","man_with_skullcap","male","boy","chinese"]},"woman-with-headscarf":{"a":"Woman with Headscarf","b":"1F9D5","j":["headscarf","hijab","mantilla","tichel","bandana","head kerchief","female"]},"person-in-tuxedo":{"a":"Person in Tuxedo","b":"1F935","j":["groom","person","tuxedo","man_in_tuxedo","couple","marriage","wedding"]},"man-in-tuxedo":{"a":"Man in Tuxedo","b":"1F935-200D-2642-FE0F","j":["man","tuxedo","formal","fashion"]},"woman-in-tuxedo":{"a":"Woman in Tuxedo","b":"1F935-200D-2640-FE0F","j":["tuxedo","woman","formal","fashion"]},"person-with-veil":{"a":"Person with Veil","b":"1F470","j":["bride","person","veil","wedding","bride_with_veil","couple","marriage","woman"]},"man-with-veil":{"a":"Man with Veil","b":"1F470-200D-2642-FE0F","j":["man","veil","wedding","marriage"]},"woman-with-veil":{"a":"Woman with Veil","b":"1F470-200D-2640-FE0F","j":["veil","woman","wedding","marriage"]},"pregnant-woman":{"a":"Pregnant Woman","b":"1F930","j":["pregnant","woman","baby"]},"pregnant-man":{"a":"⊛ Pregnant Man","b":"1FAC3","j":["belly","bloated","full","pregnant"]},"pregnant-person":{"a":"⊛ Pregnant Person","b":"1FAC4","j":["belly","bloated","full","pregnant"]},"breastfeeding":{"a":"Breast-Feeding","b":"1F931","j":["baby","breast","breast-feeding","nursing","breast_feeding"]},"woman-feeding-baby":{"a":"Woman Feeding Baby","b":"1F469-200D-1F37C","j":["baby","feeding","nursing","woman","birth","food"]},"man-feeding-baby":{"a":"Man Feeding Baby","b":"1F468-200D-1F37C","j":["baby","feeding","man","nursing","birth","food"]},"person-feeding-baby":{"a":"Person Feeding Baby","b":"1F9D1-200D-1F37C","j":["baby","feeding","nursing","person","birth","food"]},"baby-angel":{"a":"Baby Angel","b":"1F47C","j":["angel","baby","face","fairy tale","fantasy","heaven","wings","halo"]},"santa-claus":{"a":"Santa Claus","b":"1F385","j":["celebration","Christmas","claus","father","santa","festival","man","male","xmas","father christmas"]},"mrs-claus":{"a":"Mrs. Claus","b":"1F936","j":["celebration","Christmas","claus","mother","Mrs.","woman","female","xmas","mother christmas"]},"mx-claus":{"a":"Mx Claus","b":"1F9D1-200D-1F384","j":["Claus, christmas","christmas"]},"superhero":{"a":"Superhero","b":"1F9B8","j":["good","hero","heroine","superpower","marvel"]},"man-superhero":{"a":"Man Superhero","b":"1F9B8-200D-2642-FE0F","j":["good","hero","man","superpower","male","superpowers"]},"woman-superhero":{"a":"Woman Superhero","b":"1F9B8-200D-2640-FE0F","j":["good","hero","heroine","superpower","woman","female","superpowers"]},"supervillain":{"a":"Supervillain","b":"1F9B9","j":["criminal","evil","superpower","villain","marvel"]},"man-supervillain":{"a":"Man Supervillain","b":"1F9B9-200D-2642-FE0F","j":["criminal","evil","man","superpower","villain","male","bad","hero","superpowers"]},"woman-supervillain":{"a":"Woman Supervillain","b":"1F9B9-200D-2640-FE0F","j":["criminal","evil","superpower","villain","woman","female","bad","heroine","superpowers"]},"mage":{"a":"Mage","b":"1F9D9","j":["sorcerer","sorceress","witch","wizard","magic"]},"man-mage":{"a":"Man Mage","b":"1F9D9-200D-2642-FE0F","j":["sorcerer","wizard","man","male","mage"]},"woman-mage":{"a":"Woman Mage","b":"1F9D9-200D-2640-FE0F","j":["sorceress","witch","woman","female","mage"]},"fairy":{"a":"Fairy","b":"1F9DA","j":["Oberon","Puck","Titania","wings","magical"]},"man-fairy":{"a":"Man Fairy","b":"1F9DA-200D-2642-FE0F","j":["Oberon","Puck","man","male"]},"woman-fairy":{"a":"Woman Fairy","b":"1F9DA-200D-2640-FE0F","j":["Titania","woman","female"]},"vampire":{"a":"Vampire","b":"1F9DB","j":["Dracula","undead","blood","twilight"]},"man-vampire":{"a":"Man Vampire","b":"1F9DB-200D-2642-FE0F","j":["Dracula","undead","man","male","dracula"]},"woman-vampire":{"a":"Woman Vampire","b":"1F9DB-200D-2640-FE0F","j":["undead","woman","female"]},"merperson":{"a":"Merperson","b":"1F9DC","j":["mermaid","merman","merwoman","sea"]},"merman":{"a":"Merman","b":"1F9DC-200D-2642-FE0F","j":["Triton","man","male","triton"]},"mermaid":{"a":"Mermaid","b":"1F9DC-200D-2640-FE0F","j":["merwoman","woman","female","ariel"]},"elf":{"a":"Elf","b":"1F9DD","j":["magical","LOTR style"]},"man-elf":{"a":"Man Elf","b":"1F9DD-200D-2642-FE0F","j":["magical","man","male"]},"woman-elf":{"a":"Woman Elf","b":"1F9DD-200D-2640-FE0F","j":["magical","woman","female"]},"genie":{"a":"Genie","b":"1F9DE","j":["djinn","(non-human color)","magical","wishes"]},"man-genie":{"a":"Man Genie","b":"1F9DE-200D-2642-FE0F","j":["djinn","man","male"]},"woman-genie":{"a":"Woman Genie","b":"1F9DE-200D-2640-FE0F","j":["djinn","woman","female"]},"zombie":{"a":"Zombie","b":"1F9DF","j":["undead","walking dead","(non-human color)","dead"]},"man-zombie":{"a":"Man Zombie","b":"1F9DF-200D-2642-FE0F","j":["undead","walking dead","man","male","dracula"]},"woman-zombie":{"a":"Woman Zombie","b":"1F9DF-200D-2640-FE0F","j":["undead","walking dead","woman","female"]},"troll":{"a":"⊛ Troll","b":"1F9CC","j":["fairy tale","fantasy","monster"]},"person-getting-massage":{"a":"Person Getting Massage","b":"1F486","j":["face","massage","salon","relax"]},"man-getting-massage":{"a":"Man Getting Massage","b":"1F486-200D-2642-FE0F","j":["face","man","massage","male","boy","head"]},"woman-getting-massage":{"a":"Woman Getting Massage","b":"1F486-200D-2640-FE0F","j":["face","massage","woman","female","girl","head"]},"person-getting-haircut":{"a":"Person Getting Haircut","b":"1F487","j":["barber","beauty","haircut","parlor","hairstyle"]},"man-getting-haircut":{"a":"Man Getting Haircut","b":"1F487-200D-2642-FE0F","j":["haircut","man","male","boy"]},"woman-getting-haircut":{"a":"Woman Getting Haircut","b":"1F487-200D-2640-FE0F","j":["haircut","woman","female","girl"]},"person-walking":{"a":"Person Walking","b":"1F6B6","j":["hike","walk","walking","move"]},"man-walking":{"a":"Man Walking","b":"1F6B6-200D-2642-FE0F","j":["hike","man","walk","human","feet","steps"]},"woman-walking":{"a":"Woman Walking","b":"1F6B6-200D-2640-FE0F","j":["hike","walk","woman","human","feet","steps","female"]},"person-standing":{"a":"Person Standing","b":"1F9CD","j":["stand","standing","still"]},"man-standing":{"a":"Man Standing","b":"1F9CD-200D-2642-FE0F","j":["man","standing","still"]},"woman-standing":{"a":"Woman Standing","b":"1F9CD-200D-2640-FE0F","j":["standing","woman","still"]},"person-kneeling":{"a":"Person Kneeling","b":"1F9CE","j":["kneel","kneeling","pray","respectful"]},"man-kneeling":{"a":"Man Kneeling","b":"1F9CE-200D-2642-FE0F","j":["kneeling","man","pray","respectful"]},"woman-kneeling":{"a":"Woman Kneeling","b":"1F9CE-200D-2640-FE0F","j":["kneeling","woman","respectful","pray"]},"person-with-white-cane":{"a":"Person with White Cane","b":"1F9D1-200D-1F9AF","j":["accessibility","blind","person_with_probing_cane"]},"man-with-white-cane":{"a":"Man with White Cane","b":"1F468-200D-1F9AF","j":["accessibility","blind","man","man_with_probing_cane"]},"woman-with-white-cane":{"a":"Woman with White Cane","b":"1F469-200D-1F9AF","j":["accessibility","blind","woman","woman_with_probing_cane"]},"person-in-motorized-wheelchair":{"a":"Person in Motorized Wheelchair","b":"1F9D1-200D-1F9BC","j":["accessibility","wheelchair","disability"]},"man-in-motorized-wheelchair":{"a":"Man in Motorized Wheelchair","b":"1F468-200D-1F9BC","j":["accessibility","man","wheelchair","disability"]},"woman-in-motorized-wheelchair":{"a":"Woman in Motorized Wheelchair","b":"1F469-200D-1F9BC","j":["accessibility","wheelchair","woman","disability"]},"person-in-manual-wheelchair":{"a":"Person in Manual Wheelchair","b":"1F9D1-200D-1F9BD","j":["accessibility","wheelchair","disability"]},"man-in-manual-wheelchair":{"a":"Man in Manual Wheelchair","b":"1F468-200D-1F9BD","j":["accessibility","man","wheelchair","disability"]},"woman-in-manual-wheelchair":{"a":"Woman in Manual Wheelchair","b":"1F469-200D-1F9BD","j":["accessibility","wheelchair","woman","disability"]},"person-running":{"a":"Person Running","b":"1F3C3","j":["marathon","running","move"]},"man-running":{"a":"Man Running","b":"1F3C3-200D-2642-FE0F","j":["man","marathon","racing","running","walking","exercise","race"]},"woman-running":{"a":"Woman Running","b":"1F3C3-200D-2640-FE0F","j":["marathon","racing","running","woman","walking","exercise","race","female"]},"woman-dancing":{"a":"Woman Dancing","b":"1F483","j":["dance","dancing","woman","female","girl","fun"]},"man-dancing":{"a":"Man Dancing","b":"1F57A","j":["dance","dancing","man","male","boy","fun","dancer"]},"person-in-suit-levitating":{"a":"Person in Suit Levitating","b":"1F574","j":["business","person","suit","man_in_suit_levitating","levitate","hover","jump"]},"people-with-bunny-ears":{"a":"People with Bunny Ears","b":"1F46F","j":["bunny ear","dancer","partying","perform","costume"]},"men-with-bunny-ears":{"a":"Men with Bunny Ears","b":"1F46F-200D-2642-FE0F","j":["bunny ear","dancer","men","partying","male","bunny","boys"]},"women-with-bunny-ears":{"a":"Women with Bunny Ears","b":"1F46F-200D-2640-FE0F","j":["bunny ear","dancer","partying","women","female","bunny","girls"]},"person-in-steamy-room":{"a":"Person in Steamy Room","b":"1F9D6","j":["sauna","steam room","hamam","steambath","relax","spa"]},"man-in-steamy-room":{"a":"Man in Steamy Room","b":"1F9D6-200D-2642-FE0F","j":["sauna","steam room","male","man","spa","steamroom"]},"woman-in-steamy-room":{"a":"Woman in Steamy Room","b":"1F9D6-200D-2640-FE0F","j":["sauna","steam room","female","woman","spa","steamroom"]},"person-climbing":{"a":"Person Climbing","b":"1F9D7","j":["climber","sport"]},"man-climbing":{"a":"Man Climbing","b":"1F9D7-200D-2642-FE0F","j":["climber","sports","hobby","man","male","rock"]},"woman-climbing":{"a":"Woman Climbing","b":"1F9D7-200D-2640-FE0F","j":["climber","sports","hobby","woman","female","rock"]},"person-fencing":{"a":"Person Fencing","b":"1F93A","j":["fencer","fencing","sword","sports"]},"horse-racing":{"a":"Horse Racing","b":"1F3C7","j":["horse","jockey","racehorse","racing","animal","betting","competition","gambling","luck"]},"skier":{"a":"Skier","b":"26F7","j":["ski","snow","sports","winter"]},"snowboarder":{"a":"Snowboarder","b":"1F3C2","j":["ski","snow","snowboard","sports","winter"]},"person-golfing":{"a":"Person Golfing","b":"1F3CC","j":["ball","golf","sports","business"]},"man-golfing":{"a":"Man Golfing","b":"1F3CC-FE0F-200D-2642-FE0F","j":["golf","man","sport"]},"woman-golfing":{"a":"Woman Golfing","b":"1F3CC-FE0F-200D-2640-FE0F","j":["golf","woman","sports","business","female"]},"person-surfing":{"a":"Person Surfing","b":"1F3C4","j":["surfing","sport","sea"]},"man-surfing":{"a":"Man Surfing","b":"1F3C4-200D-2642-FE0F","j":["man","surfing","sports","ocean","sea","summer","beach"]},"woman-surfing":{"a":"Woman Surfing","b":"1F3C4-200D-2640-FE0F","j":["surfing","woman","sports","ocean","sea","summer","beach","female"]},"person-rowing-boat":{"a":"Person Rowing Boat","b":"1F6A3","j":["boat","rowboat","sport","move"]},"man-rowing-boat":{"a":"Man Rowing Boat","b":"1F6A3-200D-2642-FE0F","j":["boat","man","rowboat","sports","hobby","water","ship"]},"woman-rowing-boat":{"a":"Woman Rowing Boat","b":"1F6A3-200D-2640-FE0F","j":["boat","rowboat","woman","sports","hobby","water","ship","female"]},"person-swimming":{"a":"Person Swimming","b":"1F3CA","j":["swim","sport","pool"]},"man-swimming":{"a":"Man Swimming","b":"1F3CA-200D-2642-FE0F","j":["man","swim","sports","exercise","human","athlete","water","summer"]},"woman-swimming":{"a":"Woman Swimming","b":"1F3CA-200D-2640-FE0F","j":["swim","woman","sports","exercise","human","athlete","water","summer","female"]},"person-bouncing-ball":{"a":"Person Bouncing Ball","b":"26F9","j":["ball","sports","human"]},"man-bouncing-ball":{"a":"Man Bouncing Ball","b":"26F9-FE0F-200D-2642-FE0F","j":["ball","man","sport"]},"woman-bouncing-ball":{"a":"Woman Bouncing Ball","b":"26F9-FE0F-200D-2640-FE0F","j":["ball","woman","sports","human","female"]},"person-lifting-weights":{"a":"Person Lifting Weights","b":"1F3CB","j":["lifter","weight","sports","training","exercise"]},"man-lifting-weights":{"a":"Man Lifting Weights","b":"1F3CB-FE0F-200D-2642-FE0F","j":["man","weight lifter","sport"]},"woman-lifting-weights":{"a":"Woman Lifting Weights","b":"1F3CB-FE0F-200D-2640-FE0F","j":["weight lifter","woman","sports","training","exercise","female"]},"person-biking":{"a":"Person Biking","b":"1F6B4","j":["bicycle","biking","cyclist","sport","move"]},"man-biking":{"a":"Man Biking","b":"1F6B4-200D-2642-FE0F","j":["bicycle","biking","cyclist","man","sports","bike","exercise","hipster"]},"woman-biking":{"a":"Woman Biking","b":"1F6B4-200D-2640-FE0F","j":["bicycle","biking","cyclist","woman","sports","bike","exercise","hipster","female"]},"person-mountain-biking":{"a":"Person Mountain Biking","b":"1F6B5","j":["bicycle","bicyclist","bike","cyclist","mountain","sport","move"]},"man-mountain-biking":{"a":"Man Mountain Biking","b":"1F6B5-200D-2642-FE0F","j":["bicycle","bike","cyclist","man","mountain","transportation","sports","human","race"]},"woman-mountain-biking":{"a":"Woman Mountain Biking","b":"1F6B5-200D-2640-FE0F","j":["bicycle","bike","biking","cyclist","mountain","woman","transportation","sports","human","race","female"]},"person-cartwheeling":{"a":"Person Cartwheeling","b":"1F938","j":["cartwheel","gymnastics","sport","gymnastic"]},"man-cartwheeling":{"a":"Man Cartwheeling","b":"1F938-200D-2642-FE0F","j":["cartwheel","gymnastics","man"]},"woman-cartwheeling":{"a":"Woman Cartwheeling","b":"1F938-200D-2640-FE0F","j":["cartwheel","gymnastics","woman"]},"people-wrestling":{"a":"People Wrestling","b":"1F93C","j":["wrestle","wrestler","sport"]},"men-wrestling":{"a":"Men Wrestling","b":"1F93C-200D-2642-FE0F","j":["men","wrestle","sports","wrestlers"]},"women-wrestling":{"a":"Women Wrestling","b":"1F93C-200D-2640-FE0F","j":["women","wrestle","sports","wrestlers"]},"person-playing-water-polo":{"a":"Person Playing Water Polo","b":"1F93D","j":["polo","water","sport"]},"man-playing-water-polo":{"a":"Man Playing Water Polo","b":"1F93D-200D-2642-FE0F","j":["man","water polo","sports","pool"]},"woman-playing-water-polo":{"a":"Woman Playing Water Polo","b":"1F93D-200D-2640-FE0F","j":["water polo","woman","sports","pool"]},"person-playing-handball":{"a":"Person Playing Handball","b":"1F93E","j":["ball","handball","sport"]},"man-playing-handball":{"a":"Man Playing Handball","b":"1F93E-200D-2642-FE0F","j":["handball","man","sports"]},"woman-playing-handball":{"a":"Woman Playing Handball","b":"1F93E-200D-2640-FE0F","j":["handball","woman","sports"]},"person-juggling":{"a":"Person Juggling","b":"1F939","j":["balance","juggle","multitask","skill","performance"]},"man-juggling":{"a":"Man Juggling","b":"1F939-200D-2642-FE0F","j":["juggling","man","multitask","juggle","balance","skill"]},"woman-juggling":{"a":"Woman Juggling","b":"1F939-200D-2640-FE0F","j":["juggling","multitask","woman","juggle","balance","skill"]},"person-in-lotus-position":{"a":"Person in Lotus Position","b":"1F9D8","j":["meditation","yoga","serenity","meditate"]},"man-in-lotus-position":{"a":"Man in Lotus Position","b":"1F9D8-200D-2642-FE0F","j":["meditation","yoga","man","male","serenity","zen","mindfulness"]},"woman-in-lotus-position":{"a":"Woman in Lotus Position","b":"1F9D8-200D-2640-FE0F","j":["meditation","yoga","woman","female","serenity","zen","mindfulness"]},"person-taking-bath":{"a":"Person Taking Bath","b":"1F6C0","j":["bath","bathtub","clean","shower","bathroom"]},"person-in-bed":{"a":"Person in Bed","b":"1F6CC","j":["hotel","sleep","bed","rest"]},"people-holding-hands":{"a":"People Holding Hands","b":"1F9D1-200D-1F91D-200D-1F9D1","j":["couple","hand","hold","holding hands","person","friendship"]},"women-holding-hands":{"a":"Women Holding Hands","b":"1F46D","j":["couple","hand","holding hands","women","pair","friendship","love","like","female","people","human"]},"woman-and-man-holding-hands":{"a":"Woman and Man Holding Hands","b":"1F46B","j":["couple","hand","hold","holding hands","man","woman","pair","people","human","love","date","dating","like","affection","valentines","marriage"]},"men-holding-hands":{"a":"Men Holding Hands","b":"1F46C","j":["couple","Gemini","holding hands","man","men","twins","zodiac","pair","love","like","bromance","friendship","people","human"]},"kiss":{"a":"Kiss","b":"1F48F","j":["couple","pair","valentines","love","like","dating","marriage"]},"kiss-woman-man":{"a":"Kiss: Woman, Man","b":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F468","j":["couple","kiss","man","woman","love"]},"kiss-man-man":{"a":"Kiss: Man, Man","b":"1F468-200D-2764-FE0F-200D-1F48B-200D-1F468","j":["couple","kiss","man","pair","valentines","love","like","dating","marriage"]},"kiss-woman-woman":{"a":"Kiss: Woman, Woman","b":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F469","j":["couple","kiss","woman","pair","valentines","love","like","dating","marriage"]},"couple-with-heart":{"a":"Couple with Heart","b":"1F491","j":["couple","love","pair","like","affection","human","dating","valentines","marriage"]},"couple-with-heart-woman-man":{"a":"Couple with Heart: Woman, Man","b":"1F469-200D-2764-FE0F-200D-1F468","j":["couple","couple with heart","love","man","woman"]},"couple-with-heart-man-man":{"a":"Couple with Heart: Man, Man","b":"1F468-200D-2764-FE0F-200D-1F468","j":["couple","couple with heart","love","man","pair","like","affection","human","dating","valentines","marriage"]},"couple-with-heart-woman-woman":{"a":"Couple with Heart: Woman, Woman","b":"1F469-200D-2764-FE0F-200D-1F469","j":["couple","couple with heart","love","woman","pair","like","affection","human","dating","valentines","marriage"]},"family":{"a":"Family","b":"1F46A","j":["home","parents","child","mom","dad","father","mother","people","human"]},"family-man-woman-boy":{"a":"Family: Man, Woman, Boy","b":"1F468-200D-1F469-200D-1F466","j":["boy","family","man","woman","love"]},"family-man-woman-girl":{"a":"Family: Man, Woman, Girl","b":"1F468-200D-1F469-200D-1F467","j":["family","girl","man","woman","home","parents","people","human","child"]},"family-man-woman-girl-boy":{"a":"Family: Man, Woman, Girl, Boy","b":"1F468-200D-1F469-200D-1F467-200D-1F466","j":["boy","family","girl","man","woman","home","parents","people","human","children"]},"family-man-woman-boy-boy":{"a":"Family: Man, Woman, Boy, Boy","b":"1F468-200D-1F469-200D-1F466-200D-1F466","j":["boy","family","man","woman","home","parents","people","human","children"]},"family-man-woman-girl-girl":{"a":"Family: Man, Woman, Girl, Girl","b":"1F468-200D-1F469-200D-1F467-200D-1F467","j":["family","girl","man","woman","home","parents","people","human","children"]},"family-man-man-boy":{"a":"Family: Man, Man, Boy","b":"1F468-200D-1F468-200D-1F466","j":["boy","family","man","home","parents","people","human","children"]},"family-man-man-girl":{"a":"Family: Man, Man, Girl","b":"1F468-200D-1F468-200D-1F467","j":["family","girl","man","home","parents","people","human","children"]},"family-man-man-girl-boy":{"a":"Family: Man, Man, Girl, Boy","b":"1F468-200D-1F468-200D-1F467-200D-1F466","j":["boy","family","girl","man","home","parents","people","human","children"]},"family-man-man-boy-boy":{"a":"Family: Man, Man, Boy, Boy","b":"1F468-200D-1F468-200D-1F466-200D-1F466","j":["boy","family","man","home","parents","people","human","children"]},"family-man-man-girl-girl":{"a":"Family: Man, Man, Girl, Girl","b":"1F468-200D-1F468-200D-1F467-200D-1F467","j":["family","girl","man","home","parents","people","human","children"]},"family-woman-woman-boy":{"a":"Family: Woman, Woman, Boy","b":"1F469-200D-1F469-200D-1F466","j":["boy","family","woman","home","parents","people","human","children"]},"family-woman-woman-girl":{"a":"Family: Woman, Woman, Girl","b":"1F469-200D-1F469-200D-1F467","j":["family","girl","woman","home","parents","people","human","children"]},"family-woman-woman-girl-boy":{"a":"Family: Woman, Woman, Girl, Boy","b":"1F469-200D-1F469-200D-1F467-200D-1F466","j":["boy","family","girl","woman","home","parents","people","human","children"]},"family-woman-woman-boy-boy":{"a":"Family: Woman, Woman, Boy, Boy","b":"1F469-200D-1F469-200D-1F466-200D-1F466","j":["boy","family","woman","home","parents","people","human","children"]},"family-woman-woman-girl-girl":{"a":"Family: Woman, Woman, Girl, Girl","b":"1F469-200D-1F469-200D-1F467-200D-1F467","j":["family","girl","woman","home","parents","people","human","children"]},"family-man-boy":{"a":"Family: Man, Boy","b":"1F468-200D-1F466","j":["boy","family","man","home","parent","people","human","child"]},"family-man-boy-boy":{"a":"Family: Man, Boy, Boy","b":"1F468-200D-1F466-200D-1F466","j":["boy","family","man","home","parent","people","human","children"]},"family-man-girl":{"a":"Family: Man, Girl","b":"1F468-200D-1F467","j":["family","girl","man","home","parent","people","human","child"]},"family-man-girl-boy":{"a":"Family: Man, Girl, Boy","b":"1F468-200D-1F467-200D-1F466","j":["boy","family","girl","man","home","parent","people","human","children"]},"family-man-girl-girl":{"a":"Family: Man, Girl, Girl","b":"1F468-200D-1F467-200D-1F467","j":["family","girl","man","home","parent","people","human","children"]},"family-woman-boy":{"a":"Family: Woman, Boy","b":"1F469-200D-1F466","j":["boy","family","woman","home","parent","people","human","child"]},"family-woman-boy-boy":{"a":"Family: Woman, Boy, Boy","b":"1F469-200D-1F466-200D-1F466","j":["boy","family","woman","home","parent","people","human","children"]},"family-woman-girl":{"a":"Family: Woman, Girl","b":"1F469-200D-1F467","j":["family","girl","woman","home","parent","people","human","child"]},"family-woman-girl-boy":{"a":"Family: Woman, Girl, Boy","b":"1F469-200D-1F467-200D-1F466","j":["boy","family","girl","woman","home","parent","people","human","children"]},"family-woman-girl-girl":{"a":"Family: Woman, Girl, Girl","b":"1F469-200D-1F467-200D-1F467","j":["family","girl","woman","home","parent","people","human","children"]},"speaking-head":{"a":"Speaking Head","b":"1F5E3","j":["face","head","silhouette","speak","speaking","user","person","human","sing","say","talk"]},"bust-in-silhouette":{"a":"Bust in Silhouette","b":"1F464","j":["bust","silhouette","user","person","human"]},"busts-in-silhouette":{"a":"Busts in Silhouette","b":"1F465","j":["bust","silhouette","user","person","human","group","team"]},"people-hugging":{"a":"People Hugging","b":"1FAC2","j":["goodbye","hello","hug","thanks","care"]},"footprints":{"a":"Footprints","b":"1F463","j":["clothing","footprint","print","feet","tracking","walking","beach"]},"red-hair":{"a":"Red Hair","b":"1F9B0","j":["ginger","red hair","redhead"]},"curly-hair":{"a":"Curly Hair","b":"1F9B1","j":["afro","curly","curly hair","ringlets"]},"white-hair":{"a":"White Hair","b":"1F9B3","j":["gray","hair","old","white"]},"bald":{"a":"Bald","b":"1F9B2","j":["bald","chemotherapy","hairless","no hair","shaven"]},"monkey-face":{"a":"Monkey Face","b":"1F435","j":["face","monkey","animal","nature","circus"]},"monkey":{"a":"Monkey","b":"1F412","j":["animal","nature","banana","circus"]},"gorilla":{"a":"Gorilla","b":"1F98D","j":["animal","nature","circus"]},"orangutan":{"a":"Orangutan","b":"1F9A7","j":["ape","animal"]},"dog-face":{"a":"Dog Face","b":"1F436","j":["dog","face","pet","animal","friend","nature","woof","puppy","faithful"]},"dog":{"a":"Dog","b":"1F415","j":["pet","animal","nature","friend","doge","faithful"]},"guide-dog":{"a":"Guide Dog","b":"1F9AE","j":["accessibility","blind","guide","animal"]},"service-dog":{"a":"Service Dog","b":"1F415-200D-1F9BA","j":["accessibility","assistance","dog","service","blind","animal"]},"poodle":{"a":"Poodle","b":"1F429","j":["dog","animal","101","nature","pet"]},"wolf":{"a":"Wolf","b":"1F43A","j":["face","animal","nature","wild"]},"fox":{"a":"Fox","b":"1F98A","j":["face","animal","nature"]},"raccoon":{"a":"Raccoon","b":"1F99D","j":["curious","sly","animal","nature"]},"cat-face":{"a":"Cat Face","b":"1F431","j":["cat","face","pet","animal","meow","nature","kitten"]},"cat":{"a":"Cat","b":"1F408","j":["pet","animal","meow","cats"]},"black-cat":{"a":"Black Cat","b":"1F408-200D-2B1B","j":["black","cat","unlucky","superstition","luck"]},"lion":{"a":"Lion","b":"1F981","j":["face","Leo","zodiac","animal","nature"]},"tiger-face":{"a":"Tiger Face","b":"1F42F","j":["face","tiger","animal","cat","danger","wild","nature","roar"]},"tiger":{"a":"Tiger","b":"1F405","j":["animal","nature","roar"]},"leopard":{"a":"Leopard","b":"1F406","j":["animal","nature"]},"horse-face":{"a":"Horse Face","b":"1F434","j":["face","horse","animal","brown","nature"]},"horse":{"a":"Horse","b":"1F40E","j":["equestrian","racehorse","racing","animal","gamble","luck"]},"unicorn":{"a":"Unicorn","b":"1F984","j":["face","animal","nature","mystical"]},"zebra":{"a":"Zebra","b":"1F993","j":["stripe","animal","nature","stripes","safari"]},"deer":{"a":"Deer","b":"1F98C","j":["animal","nature","horns","venison"]},"bison":{"a":"Bison","b":"1F9AC","j":["buffalo","herd","wisent","ox"]},"cow-face":{"a":"Cow Face","b":"1F42E","j":["cow","face","beef","ox","animal","nature","moo","milk"]},"ox":{"a":"Ox","b":"1F402","j":["bull","Taurus","zodiac","animal","cow","beef"]},"water-buffalo":{"a":"Water Buffalo","b":"1F403","j":["buffalo","water","animal","nature","ox","cow"]},"cow":{"a":"Cow","b":"1F404","j":["beef","ox","animal","nature","moo","milk"]},"pig-face":{"a":"Pig Face","b":"1F437","j":["face","pig","animal","oink","nature"]},"pig":{"a":"Pig","b":"1F416","j":["sow","animal","nature"]},"boar":{"a":"Boar","b":"1F417","j":["pig","animal","nature"]},"pig-nose":{"a":"Pig Nose","b":"1F43D","j":["face","nose","pig","animal","oink"]},"ram":{"a":"Ram","b":"1F40F","j":["Aries","male","sheep","zodiac","animal","nature"]},"ewe":{"a":"Ewe","b":"1F411","j":["female","sheep","animal","nature","wool","shipit"]},"goat":{"a":"Goat","b":"1F410","j":["Capricorn","zodiac","animal","nature"]},"camel":{"a":"Camel","b":"1F42A","j":["dromedary","hump","animal","hot","desert"]},"twohump-camel":{"a":"Two-Hump Camel","b":"1F42B","j":["bactrian","camel","hump","two-hump camel","two_hump_camel","animal","nature","hot","desert"]},"llama":{"a":"Llama","b":"1F999","j":["alpaca","guanaco","vicuña","wool","animal","nature"]},"giraffe":{"a":"Giraffe","b":"1F992","j":["spots","animal","nature","safari"]},"elephant":{"a":"Elephant","b":"1F418","j":["animal","nature","nose","th","circus"]},"mammoth":{"a":"Mammoth","b":"1F9A3","j":["extinction","large","tusk","woolly","elephant","tusks"]},"rhinoceros":{"a":"Rhinoceros","b":"1F98F","j":["animal","nature","horn"]},"hippopotamus":{"a":"Hippopotamus","b":"1F99B","j":["hippo","animal","nature"]},"mouse-face":{"a":"Mouse Face","b":"1F42D","j":["face","mouse","animal","nature","cheese_wedge","rodent"]},"mouse":{"a":"Mouse","b":"1F401","j":["animal","nature","rodent"]},"rat":{"a":"Rat","b":"1F400","j":["animal","mouse","rodent"]},"hamster":{"a":"Hamster","b":"1F439","j":["face","pet","animal","nature"]},"rabbit-face":{"a":"Rabbit Face","b":"1F430","j":["bunny","face","pet","rabbit","animal","nature","spring","magic"]},"rabbit":{"a":"Rabbit","b":"1F407","j":["bunny","pet","animal","nature","magic","spring"]},"chipmunk":{"a":"Chipmunk","b":"1F43F","j":["squirrel","animal","nature","rodent"]},"beaver":{"a":"Beaver","b":"1F9AB","j":["dam","animal","rodent"]},"hedgehog":{"a":"Hedgehog","b":"1F994","j":["spiny","animal","nature"]},"bat":{"a":"Bat","b":"1F987","j":["vampire","animal","nature","blind"]},"bear":{"a":"Bear","b":"1F43B","j":["face","animal","nature","wild"]},"polar-bear":{"a":"Polar Bear","b":"1F43B-200D-2744-FE0F","j":["arctic","bear","white","animal"]},"koala":{"a":"Koala","b":"1F428","j":["face","marsupial","animal","nature"]},"panda":{"a":"Panda","b":"1F43C","j":["face","animal","nature"]},"sloth":{"a":"Sloth","b":"1F9A5","j":["lazy","slow","animal"]},"otter":{"a":"Otter","b":"1F9A6","j":["fishing","playful","animal"]},"skunk":{"a":"Skunk","b":"1F9A8","j":["stink","animal"]},"kangaroo":{"a":"Kangaroo","b":"1F998","j":["Australia","joey","jump","marsupial","animal","nature","australia","hop"]},"badger":{"a":"Badger","b":"1F9A1","j":["honey badger","pester","animal","nature","honey"]},"paw-prints":{"a":"Paw Prints","b":"1F43E","j":["feet","paw","print","animal","tracking","footprints","dog","cat","pet"]},"turkey":{"a":"Turkey","b":"1F983","j":["bird","animal"]},"chicken":{"a":"Chicken","b":"1F414","j":["bird","animal","cluck","nature"]},"rooster":{"a":"Rooster","b":"1F413","j":["bird","animal","nature","chicken"]},"hatching-chick":{"a":"Hatching Chick","b":"1F423","j":["baby","bird","chick","hatching","animal","chicken","egg","born"]},"baby-chick":{"a":"Baby Chick","b":"1F424","j":["baby","bird","chick","animal","chicken"]},"frontfacing-baby-chick":{"a":"Front-Facing Baby Chick","b":"1F425","j":["baby","bird","chick","front-facing baby chick","front_facing_baby_chick","animal","chicken"]},"bird":{"a":"Bird","b":"1F426","j":["animal","nature","fly","tweet","spring"]},"penguin":{"a":"Penguin","b":"1F427","j":["bird","animal","nature"]},"dove":{"a":"Dove","b":"1F54A","j":["bird","fly","peace","animal"]},"eagle":{"a":"Eagle","b":"1F985","j":["bird","animal","nature"]},"duck":{"a":"Duck","b":"1F986","j":["bird","animal","nature","mallard"]},"swan":{"a":"Swan","b":"1F9A2","j":["bird","cygnet","ugly duckling","animal","nature"]},"owl":{"a":"Owl","b":"1F989","j":["bird","wise","animal","nature","hoot"]},"dodo":{"a":"Dodo","b":"1F9A4","j":["extinction","large","Mauritius","animal","bird"]},"feather":{"a":"Feather","b":"1FAB6","j":["bird","flight","light","plumage","fly"]},"flamingo":{"a":"Flamingo","b":"1F9A9","j":["flamboyant","tropical","animal"]},"peacock":{"a":"Peacock","b":"1F99A","j":["bird","ostentatious","peahen","proud","animal","nature"]},"parrot":{"a":"Parrot","b":"1F99C","j":["bird","pirate","talk","animal","nature"]},"frog":{"a":"Frog","b":"1F438","j":["face","animal","nature","croak","toad"]},"crocodile":{"a":"Crocodile","b":"1F40A","j":["animal","nature","reptile","lizard","alligator"]},"turtle":{"a":"Turtle","b":"1F422","j":["terrapin","tortoise","animal","slow","nature"]},"lizard":{"a":"Lizard","b":"1F98E","j":["reptile","animal","nature"]},"snake":{"a":"Snake","b":"1F40D","j":["bearer","Ophiuchus","serpent","zodiac","animal","evil","nature","hiss","python"]},"dragon-face":{"a":"Dragon Face","b":"1F432","j":["dragon","face","fairy tale","animal","myth","nature","chinese","green"]},"dragon":{"a":"Dragon","b":"1F409","j":["fairy tale","animal","myth","nature","chinese","green"]},"sauropod":{"a":"Sauropod","b":"1F995","j":["brachiosaurus","brontosaurus","diplodocus","animal","nature","dinosaur","extinct"]},"trex":{"a":"T-Rex","b":"1F996","j":["Tyrannosaurus Rex","t_rex","animal","nature","dinosaur","tyrannosaurus","extinct"]},"spouting-whale":{"a":"Spouting Whale","b":"1F433","j":["face","spouting","whale","animal","nature","sea","ocean"]},"whale":{"a":"Whale","b":"1F40B","j":["animal","nature","sea","ocean"]},"dolphin":{"a":"Dolphin","b":"1F42C","j":["flipper","animal","nature","fish","sea","ocean","fins","beach"]},"seal":{"a":"Seal","b":"1F9AD","j":["sea lion","animal","creature","sea"]},"fish":{"a":"Fish","b":"1F41F","j":["Pisces","zodiac","animal","food","nature"]},"tropical-fish":{"a":"Tropical Fish","b":"1F420","j":["fish","tropical","animal","swim","ocean","beach","nemo"]},"blowfish":{"a":"Blowfish","b":"1F421","j":["fish","animal","nature","food","sea","ocean"]},"shark":{"a":"Shark","b":"1F988","j":["fish","animal","nature","sea","ocean","jaws","fins","beach"]},"octopus":{"a":"Octopus","b":"1F419","j":["animal","creature","ocean","sea","nature","beach"]},"spiral-shell":{"a":"Spiral Shell","b":"1F41A","j":["shell","spiral","nature","sea","beach"]},"coral":{"a":"⊛ Coral","b":"1FAB8","j":["ocean","reef"]},"snail":{"a":"Snail","b":"1F40C","j":["slow","animal","shell"]},"butterfly":{"a":"Butterfly","b":"1F98B","j":["insect","pretty","animal","nature","caterpillar"]},"bug":{"a":"Bug","b":"1F41B","j":["insect","animal","nature","worm"]},"ant":{"a":"Ant","b":"1F41C","j":["insect","animal","nature","bug"]},"honeybee":{"a":"Honeybee","b":"1F41D","j":["bee","insect","animal","nature","bug","spring","honey"]},"beetle":{"a":"Beetle","b":"1FAB2","j":["bug","insect"]},"lady-beetle":{"a":"Lady Beetle","b":"1F41E","j":["beetle","insect","ladybird","ladybug","animal","nature"]},"cricket":{"a":"Cricket","b":"1F997","j":["grasshopper","Orthoptera","animal","chirp"]},"cockroach":{"a":"Cockroach","b":"1FAB3","j":["insect","pest","roach","pests"]},"spider":{"a":"Spider","b":"1F577","j":["insect","animal","arachnid"]},"spider-web":{"a":"Spider Web","b":"1F578","j":["spider","web","animal","insect","arachnid","silk"]},"scorpion":{"a":"Scorpion","b":"1F982","j":["scorpio","Scorpio","zodiac","animal","arachnid"]},"mosquito":{"a":"Mosquito","b":"1F99F","j":["disease","fever","malaria","pest","virus","animal","nature","insect"]},"fly":{"a":"Fly","b":"1FAB0","j":["disease","maggot","pest","rotting","insect"]},"worm":{"a":"Worm","b":"1FAB1","j":["annelid","earthworm","parasite","animal"]},"microbe":{"a":"Microbe","b":"1F9A0","j":["amoeba","bacteria","virus","germs"]},"bouquet":{"a":"Bouquet","b":"1F490","j":["flower","flowers","nature","spring"]},"cherry-blossom":{"a":"Cherry Blossom","b":"1F338","j":["blossom","cherry","flower","nature","plant","spring"]},"white-flower":{"a":"White Flower","b":"1F4AE","j":["flower","japanese","spring"]},"lotus":{"a":"⊛ Lotus","b":"1FAB7","j":["Buddhism","flower","Hinduism","India","purity","Vietnam"]},"rosette":{"a":"Rosette","b":"1F3F5","j":["plant","flower","decoration","military"]},"rose":{"a":"Rose","b":"1F339","j":["flower","flowers","valentines","love","spring"]},"wilted-flower":{"a":"Wilted Flower","b":"1F940","j":["flower","wilted","plant","nature"]},"hibiscus":{"a":"Hibiscus","b":"1F33A","j":["flower","plant","vegetable","flowers","beach"]},"sunflower":{"a":"Sunflower","b":"1F33B","j":["flower","sun","nature","plant","fall"]},"blossom":{"a":"Blossom","b":"1F33C","j":["flower","nature","flowers","yellow"]},"tulip":{"a":"Tulip","b":"1F337","j":["flower","flowers","plant","nature","summer","spring"]},"seedling":{"a":"Seedling","b":"1F331","j":["young","plant","nature","grass","lawn","spring"]},"potted-plant":{"a":"Potted Plant","b":"1FAB4","j":["boring","grow","house","nurturing","plant","useless","greenery"]},"evergreen-tree":{"a":"Evergreen Tree","b":"1F332","j":["tree","plant","nature"]},"deciduous-tree":{"a":"Deciduous Tree","b":"1F333","j":["deciduous","shedding","tree","plant","nature"]},"palm-tree":{"a":"Palm Tree","b":"1F334","j":["palm","tree","plant","vegetable","nature","summer","beach","mojito","tropical"]},"cactus":{"a":"Cactus","b":"1F335","j":["plant","vegetable","nature"]},"sheaf-of-rice":{"a":"Sheaf of Rice","b":"1F33E","j":["ear","grain","rice","nature","plant"]},"herb":{"a":"Herb","b":"1F33F","j":["leaf","vegetable","plant","medicine","weed","grass","lawn"]},"shamrock":{"a":"Shamrock","b":"2618","j":["plant","vegetable","nature","irish","clover"]},"four-leaf-clover":{"a":"Four Leaf Clover","b":"1F340","j":["4","clover","four","four-leaf clover","leaf","vegetable","plant","nature","lucky","irish"]},"maple-leaf":{"a":"Maple Leaf","b":"1F341","j":["falling","leaf","maple","nature","plant","vegetable","ca","fall"]},"fallen-leaf":{"a":"Fallen Leaf","b":"1F342","j":["falling","leaf","nature","plant","vegetable","leaves"]},"leaf-fluttering-in-wind":{"a":"Leaf Fluttering in Wind","b":"1F343","j":["blow","flutter","leaf","wind","nature","plant","tree","vegetable","grass","lawn","spring"]},"empty-nest":{"a":"⊛ Empty Nest","b":"1FAB9","j":["nesting"]},"nest-with-eggs":{"a":"⊛ Nest with Eggs","b":"1FABA","j":["nesting"]},"grapes":{"a":"Grapes","b":"1F347","j":["fruit","grape","food","wine"]},"melon":{"a":"Melon","b":"1F348","j":["fruit","nature","food"]},"watermelon":{"a":"Watermelon","b":"1F349","j":["fruit","food","picnic","summer"]},"tangerine":{"a":"Tangerine","b":"1F34A","j":["fruit","orange","food","nature"]},"lemon":{"a":"Lemon","b":"1F34B","j":["citrus","fruit","nature"]},"banana":{"a":"Banana","b":"1F34C","j":["fruit","food","monkey"]},"pineapple":{"a":"Pineapple","b":"1F34D","j":["fruit","nature","food"]},"mango":{"a":"Mango","b":"1F96D","j":["fruit","tropical","food"]},"red-apple":{"a":"Red Apple","b":"1F34E","j":["apple","fruit","red","mac","school"]},"green-apple":{"a":"Green Apple","b":"1F34F","j":["apple","fruit","green","nature"]},"pear":{"a":"Pear","b":"1F350","j":["fruit","nature","food"]},"peach":{"a":"Peach","b":"1F351","j":["fruit","nature","food"]},"cherries":{"a":"Cherries","b":"1F352","j":["berries","cherry","fruit","red","food"]},"strawberry":{"a":"Strawberry","b":"1F353","j":["berry","fruit","food","nature"]},"blueberries":{"a":"Blueberries","b":"1FAD0","j":["berry","bilberry","blue","blueberry","fruit"]},"kiwi-fruit":{"a":"Kiwi Fruit","b":"1F95D","j":["food","fruit","kiwi"]},"tomato":{"a":"Tomato","b":"1F345","j":["fruit","vegetable","nature","food"]},"olive":{"a":"Olive","b":"1FAD2","j":["food","fruit"]},"coconut":{"a":"Coconut","b":"1F965","j":["palm","piña colada","fruit","nature","food"]},"avocado":{"a":"Avocado","b":"1F951","j":["food","fruit"]},"eggplant":{"a":"Eggplant","b":"1F346","j":["aubergine","vegetable","nature","food"]},"potato":{"a":"Potato","b":"1F954","j":["food","vegetable","tuber","vegatable","starch"]},"carrot":{"a":"Carrot","b":"1F955","j":["food","vegetable","orange"]},"ear-of-corn":{"a":"Ear of Corn","b":"1F33D","j":["corn","ear","maize","maze","food","vegetable","plant"]},"hot-pepper":{"a":"Hot Pepper","b":"1F336","j":["hot","pepper","food","spicy","chilli","chili"]},"bell-pepper":{"a":"Bell Pepper","b":"1FAD1","j":["capsicum","pepper","vegetable","fruit","plant"]},"cucumber":{"a":"Cucumber","b":"1F952","j":["food","pickle","vegetable","fruit"]},"leafy-green":{"a":"Leafy Green","b":"1F96C","j":["bok choy","cabbage","kale","lettuce","food","vegetable","plant"]},"broccoli":{"a":"Broccoli","b":"1F966","j":["wild cabbage","fruit","food","vegetable"]},"garlic":{"a":"Garlic","b":"1F9C4","j":["flavoring","food","spice","cook"]},"onion":{"a":"Onion","b":"1F9C5","j":["flavoring","cook","food","spice"]},"mushroom":{"a":"Mushroom","b":"1F344","j":["toadstool","plant","vegetable"]},"peanuts":{"a":"Peanuts","b":"1F95C","j":["food","nut","peanut","vegetable"]},"beans":{"a":"⊛ Beans","b":"1FAD8","j":["food","kidney","legume"]},"chestnut":{"a":"Chestnut","b":"1F330","j":["plant","food","squirrel"]},"bread":{"a":"Bread","b":"1F35E","j":["loaf","food","wheat","breakfast","toast"]},"croissant":{"a":"Croissant","b":"1F950","j":["bread","breakfast","food","french","roll"]},"baguette-bread":{"a":"Baguette Bread","b":"1F956","j":["baguette","bread","food","french"]},"flatbread":{"a":"Flatbread","b":"1FAD3","j":["arepa","lavash","naan","pita","flour","food"]},"pretzel":{"a":"Pretzel","b":"1F968","j":["twisted","convoluted","food","bread"]},"bagel":{"a":"Bagel","b":"1F96F","j":["bakery","breakfast","schmear","food","bread"]},"pancakes":{"a":"Pancakes","b":"1F95E","j":["breakfast","crêpe","food","hotcake","pancake","flapjacks","hotcakes"]},"waffle":{"a":"Waffle","b":"1F9C7","j":["breakfast","indecisive","iron","food"]},"cheese-wedge":{"a":"Cheese Wedge","b":"1F9C0","j":["cheese","food","chadder"]},"meat-on-bone":{"a":"Meat on Bone","b":"1F356","j":["bone","meat","good","food","drumstick"]},"poultry-leg":{"a":"Poultry Leg","b":"1F357","j":["bone","chicken","drumstick","leg","poultry","food","meat","bird","turkey"]},"cut-of-meat":{"a":"Cut of Meat","b":"1F969","j":["chop","lambchop","porkchop","steak","food","cow","meat","cut"]},"bacon":{"a":"Bacon","b":"1F953","j":["breakfast","food","meat","pork","pig"]},"hamburger":{"a":"Hamburger","b":"1F354","j":["burger","meat","fast food","beef","cheeseburger","mcdonalds","burger king"]},"french-fries":{"a":"French Fries","b":"1F35F","j":["french","fries","chips","snack","fast food"]},"pizza":{"a":"Pizza","b":"1F355","j":["cheese","slice","food","party"]},"hot-dog":{"a":"Hot Dog","b":"1F32D","j":["frankfurter","hotdog","sausage","food"]},"sandwich":{"a":"Sandwich","b":"1F96A","j":["bread","food","lunch"]},"taco":{"a":"Taco","b":"1F32E","j":["mexican","food"]},"burrito":{"a":"Burrito","b":"1F32F","j":["mexican","wrap","food"]},"tamale":{"a":"Tamale","b":"1FAD4","j":["mexican","wrapped","food","masa"]},"stuffed-flatbread":{"a":"Stuffed Flatbread","b":"1F959","j":["falafel","flatbread","food","gyro","kebab","stuffed"]},"falafel":{"a":"Falafel","b":"1F9C6","j":["chickpea","meatball","food"]},"egg":{"a":"Egg","b":"1F95A","j":["breakfast","food","chicken"]},"cooking":{"a":"Cooking","b":"1F373","j":["breakfast","egg","frying","pan","food","kitchen"]},"shallow-pan-of-food":{"a":"Shallow Pan of Food","b":"1F958","j":["casserole","food","paella","pan","shallow","cooking"]},"pot-of-food":{"a":"Pot of Food","b":"1F372","j":["pot","stew","food","meat","soup"]},"fondue":{"a":"Fondue","b":"1FAD5","j":["cheese","chocolate","melted","pot","Swiss","food"]},"bowl-with-spoon":{"a":"Bowl with Spoon","b":"1F963","j":["breakfast","cereal","congee","oatmeal","porridge","food"]},"green-salad":{"a":"Green Salad","b":"1F957","j":["food","green","salad","healthy","lettuce"]},"popcorn":{"a":"Popcorn","b":"1F37F","j":["food","movie theater","films","snack"]},"butter":{"a":"Butter","b":"1F9C8","j":["dairy","food","cook"]},"salt":{"a":"Salt","b":"1F9C2","j":["condiment","shaker"]},"canned-food":{"a":"Canned Food","b":"1F96B","j":["can","food","soup"]},"bento-box":{"a":"Bento Box","b":"1F371","j":["bento","box","food","japanese"]},"rice-cracker":{"a":"Rice Cracker","b":"1F358","j":["cracker","rice","food","japanese"]},"rice-ball":{"a":"Rice Ball","b":"1F359","j":["ball","Japanese","rice","food","japanese"]},"cooked-rice":{"a":"Cooked Rice","b":"1F35A","j":["cooked","rice","food","china","asian"]},"curry-rice":{"a":"Curry Rice","b":"1F35B","j":["curry","rice","food","spicy","hot","indian"]},"steaming-bowl":{"a":"Steaming Bowl","b":"1F35C","j":["bowl","noodle","ramen","steaming","food","japanese","chopsticks"]},"spaghetti":{"a":"Spaghetti","b":"1F35D","j":["pasta","food","italian","noodle"]},"roasted-sweet-potato":{"a":"Roasted Sweet Potato","b":"1F360","j":["potato","roasted","sweet","food","nature"]},"oden":{"a":"Oden","b":"1F362","j":["kebab","seafood","skewer","stick","food","japanese"]},"sushi":{"a":"Sushi","b":"1F363","j":["food","fish","japanese","rice"]},"fried-shrimp":{"a":"Fried Shrimp","b":"1F364","j":["fried","prawn","shrimp","tempura","food","animal","appetizer","summer"]},"fish-cake-with-swirl":{"a":"Fish Cake with Swirl","b":"1F365","j":["cake","fish","pastry","swirl","food","japan","sea","beach","narutomaki","pink","kamaboko","surimi","ramen"]},"moon-cake":{"a":"Moon Cake","b":"1F96E","j":["autumn","festival","yuèbǐng","food"]},"dango":{"a":"Dango","b":"1F361","j":["dessert","Japanese","skewer","stick","sweet","food","japanese","barbecue","meat"]},"dumpling":{"a":"Dumpling","b":"1F95F","j":["empanada","gyōza","jiaozi","pierogi","potsticker","food"]},"fortune-cookie":{"a":"Fortune Cookie","b":"1F960","j":["prophecy","food"]},"takeout-box":{"a":"Takeout Box","b":"1F961","j":["oyster pail","food","leftovers"]},"crab":{"a":"Crab","b":"1F980","j":["Cancer","zodiac","animal","crustacean"]},"lobster":{"a":"Lobster","b":"1F99E","j":["bisque","claws","seafood","animal","nature"]},"shrimp":{"a":"Shrimp","b":"1F990","j":["food","shellfish","small","animal","ocean","nature","seafood"]},"squid":{"a":"Squid","b":"1F991","j":["food","molusc","animal","nature","ocean","sea"]},"oyster":{"a":"Oyster","b":"1F9AA","j":["diving","pearl","food"]},"soft-ice-cream":{"a":"Soft Ice Cream","b":"1F366","j":["cream","dessert","ice","icecream","soft","sweet","food","hot","summer"]},"shaved-ice":{"a":"Shaved Ice","b":"1F367","j":["dessert","ice","shaved","sweet","hot","summer"]},"ice-cream":{"a":"Ice Cream","b":"1F368","j":["cream","dessert","ice","sweet","food","hot"]},"doughnut":{"a":"Doughnut","b":"1F369","j":["breakfast","dessert","donut","sweet","food","snack"]},"cookie":{"a":"Cookie","b":"1F36A","j":["dessert","sweet","food","snack","oreo","chocolate"]},"birthday-cake":{"a":"Birthday Cake","b":"1F382","j":["birthday","cake","celebration","dessert","pastry","sweet","food"]},"shortcake":{"a":"Shortcake","b":"1F370","j":["cake","dessert","pastry","slice","sweet","food"]},"cupcake":{"a":"Cupcake","b":"1F9C1","j":["bakery","sweet","food","dessert"]},"pie":{"a":"Pie","b":"1F967","j":["filling","pastry","fruit","meat","food","dessert"]},"chocolate-bar":{"a":"Chocolate Bar","b":"1F36B","j":["bar","chocolate","dessert","sweet","food","snack"]},"candy":{"a":"Candy","b":"1F36C","j":["dessert","sweet","snack","lolly"]},"lollipop":{"a":"Lollipop","b":"1F36D","j":["candy","dessert","sweet","food","snack"]},"custard":{"a":"Custard","b":"1F36E","j":["dessert","pudding","sweet","food"]},"honey-pot":{"a":"Honey Pot","b":"1F36F","j":["honey","honeypot","pot","sweet","bees","kitchen"]},"baby-bottle":{"a":"Baby Bottle","b":"1F37C","j":["baby","bottle","drink","milk","food","container"]},"glass-of-milk":{"a":"Glass of Milk","b":"1F95B","j":["drink","glass","milk","beverage","cow"]},"hot-beverage":{"a":"Hot Beverage","b":"2615","j":["beverage","coffee","drink","hot","steaming","tea","caffeine","latte","espresso"]},"teapot":{"a":"Teapot","b":"1FAD6","j":["drink","pot","tea","hot"]},"teacup-without-handle":{"a":"Teacup Without Handle","b":"1F375","j":["beverage","cup","drink","tea","teacup","bowl","breakfast","green","british"]},"sake":{"a":"Sake","b":"1F376","j":["bar","beverage","bottle","cup","drink","wine","drunk","japanese","alcohol","booze"]},"bottle-with-popping-cork":{"a":"Bottle with Popping Cork","b":"1F37E","j":["bar","bottle","cork","drink","popping","wine","celebration"]},"wine-glass":{"a":"Wine Glass","b":"1F377","j":["bar","beverage","drink","glass","wine","drunk","alcohol","booze"]},"cocktail-glass":{"a":"Cocktail Glass","b":"1F378","j":["bar","cocktail","drink","glass","drunk","alcohol","beverage","booze","mojito"]},"tropical-drink":{"a":"Tropical Drink","b":"1F379","j":["bar","drink","tropical","beverage","cocktail","summer","beach","alcohol","booze","mojito"]},"beer-mug":{"a":"Beer Mug","b":"1F37A","j":["bar","beer","drink","mug","relax","beverage","drunk","party","pub","summer","alcohol","booze"]},"clinking-beer-mugs":{"a":"Clinking Beer Mugs","b":"1F37B","j":["bar","beer","clink","drink","mug","relax","beverage","drunk","party","pub","summer","alcohol","booze"]},"clinking-glasses":{"a":"Clinking Glasses","b":"1F942","j":["celebrate","clink","drink","glass","beverage","party","alcohol","cheers","wine","champagne","toast"]},"tumbler-glass":{"a":"Tumbler Glass","b":"1F943","j":["glass","liquor","shot","tumbler","whisky","drink","beverage","drunk","alcohol","booze","bourbon","scotch"]},"pouring-liquid":{"a":"⊛ Pouring Liquid","b":"1FAD7","j":["drink","empty","glass","spill"]},"cup-with-straw":{"a":"Cup with Straw","b":"1F964","j":["juice","soda","malt","soft drink","water","drink"]},"bubble-tea":{"a":"Bubble Tea","b":"1F9CB","j":["bubble","milk","pearl","tea","taiwan","boba","milk tea","straw"]},"beverage-box":{"a":"Beverage Box","b":"1F9C3","j":["beverage","box","juice","straw","sweet","drink"]},"mate":{"a":"Mate","b":"1F9C9","j":["drink","tea","beverage"]},"ice":{"a":"Ice","b":"1F9CA","j":["cold","ice cube","iceberg","water"]},"chopsticks":{"a":"Chopsticks","b":"1F962","j":["hashi","jeotgarak","kuaizi","food"]},"fork-and-knife-with-plate":{"a":"Fork and Knife with Plate","b":"1F37D","j":["cooking","fork","knife","plate","food","eat","meal","lunch","dinner","restaurant"]},"fork-and-knife":{"a":"Fork and Knife","b":"1F374","j":["cooking","cutlery","fork","knife","kitchen"]},"spoon":{"a":"Spoon","b":"1F944","j":["tableware","cutlery","kitchen"]},"kitchen-knife":{"a":"Kitchen Knife","b":"1F52A","j":["cooking","hocho","knife","tool","weapon","blade","cutlery","kitchen"]},"jar":{"a":"⊛ Jar","b":"1FAD9","j":["condiment","container","empty","sauce","store"]},"amphora":{"a":"Amphora","b":"1F3FA","j":["Aquarius","cooking","drink","jug","zodiac","vase","jar"]},"globe-showing-europeafrica":{"a":"Globe Showing Europe-Africa","b":"1F30D","j":["Africa","earth","Europe","globe","globe showing Europe-Africa","world","globe_showing_europe_africa","international"]},"globe-showing-americas":{"a":"Globe Showing Americas","b":"1F30E","j":["Americas","earth","globe","globe showing Americas","world","USA","international"]},"globe-showing-asiaaustralia":{"a":"Globe Showing Asia-Australia","b":"1F30F","j":["Asia","Australia","earth","globe","globe showing Asia-Australia","world","globe_showing_asia_australia","east","international"]},"globe-with-meridians":{"a":"Globe with Meridians","b":"1F310","j":["earth","globe","meridians","world","international","internet","interweb","i18n"]},"world-map":{"a":"World Map","b":"1F5FA","j":["map","world","location","direction"]},"map-of-japan":{"a":"Map of Japan","b":"1F5FE","j":["Japan","map","map of Japan","nation","country","japanese","asia"]},"compass":{"a":"Compass","b":"1F9ED","j":["magnetic","navigation","orienteering"]},"snowcapped-mountain":{"a":"Snow-Capped Mountain","b":"1F3D4","j":["cold","mountain","snow","snow-capped mountain","snow_capped_mountain","photo","nature","environment","winter"]},"mountain":{"a":"Mountain","b":"26F0","j":["photo","nature","environment"]},"volcano":{"a":"Volcano","b":"1F30B","j":["eruption","mountain","photo","nature","disaster"]},"mount-fuji":{"a":"Mount Fuji","b":"1F5FB","j":["fuji","mountain","photo","nature","japanese"]},"camping":{"a":"Camping","b":"1F3D5","j":["photo","outdoors","tent"]},"beach-with-umbrella":{"a":"Beach with Umbrella","b":"1F3D6","j":["beach","umbrella","weather","summer","sunny","sand","mojito"]},"desert":{"a":"Desert","b":"1F3DC","j":["photo","warm","saharah"]},"desert-island":{"a":"Desert Island","b":"1F3DD","j":["desert","island","photo","tropical","mojito"]},"national-park":{"a":"National Park","b":"1F3DE","j":["park","photo","environment","nature"]},"stadium":{"a":"Stadium","b":"1F3DF","j":["photo","place","sports","concert","venue"]},"classical-building":{"a":"Classical Building","b":"1F3DB","j":["classical","art","culture","history"]},"building-construction":{"a":"Building Construction","b":"1F3D7","j":["construction","wip","working","progress"]},"brick":{"a":"Brick","b":"1F9F1","j":["bricks","clay","mortar","wall"]},"rock":{"a":"Rock","b":"1FAA8","j":["boulder","heavy","solid","stone"]},"wood":{"a":"Wood","b":"1FAB5","j":["log","lumber","timber","nature","trunk"]},"hut":{"a":"Hut","b":"1F6D6","j":["house","roundhouse","yurt","structure"]},"houses":{"a":"Houses","b":"1F3D8","j":["buildings","photo"]},"derelict-house":{"a":"Derelict House","b":"1F3DA","j":["derelict","house","abandon","evict","broken","building"]},"house":{"a":"House","b":"1F3E0","j":["home","building"]},"house-with-garden":{"a":"House with Garden","b":"1F3E1","j":["garden","home","house","plant","nature"]},"office-building":{"a":"Office Building","b":"1F3E2","j":["building","bureau","work"]},"japanese-post-office":{"a":"Japanese Post Office","b":"1F3E3","j":["Japanese","Japanese post office","post","building","envelope","communication"]},"post-office":{"a":"Post Office","b":"1F3E4","j":["European","post","building","email"]},"hospital":{"a":"Hospital","b":"1F3E5","j":["doctor","medicine","building","health","surgery"]},"bank":{"a":"Bank","b":"1F3E6","j":["building","money","sales","cash","business","enterprise"]},"hotel":{"a":"Hotel","b":"1F3E8","j":["building","accomodation","checkin"]},"love-hotel":{"a":"Love Hotel","b":"1F3E9","j":["hotel","love","like","affection","dating"]},"convenience-store":{"a":"Convenience Store","b":"1F3EA","j":["convenience","store","building","shopping","groceries"]},"school":{"a":"School","b":"1F3EB","j":["building","student","education","learn","teach"]},"department-store":{"a":"Department Store","b":"1F3EC","j":["department","store","building","shopping","mall"]},"factory":{"a":"Factory","b":"1F3ED","j":["building","industry","pollution","smoke"]},"japanese-castle":{"a":"Japanese Castle","b":"1F3EF","j":["castle","Japanese","photo","building"]},"castle":{"a":"Castle","b":"1F3F0","j":["European","building","royalty","history"]},"wedding":{"a":"Wedding","b":"1F492","j":["chapel","romance","love","like","affection","couple","marriage","bride","groom"]},"tokyo-tower":{"a":"Tokyo Tower","b":"1F5FC","j":["Tokyo","tower","photo","japanese"]},"statue-of-liberty":{"a":"Statue of Liberty","b":"1F5FD","j":["liberty","statue","american","newyork"]},"church":{"a":"Church","b":"26EA","j":["Christian","cross","religion","building","christ"]},"mosque":{"a":"Mosque","b":"1F54C","j":["islam","Muslim","religion","worship","minaret"]},"hindu-temple":{"a":"Hindu Temple","b":"1F6D5","j":["hindu","temple","religion"]},"synagogue":{"a":"Synagogue","b":"1F54D","j":["Jew","Jewish","religion","temple","judaism","worship","jewish"]},"shinto-shrine":{"a":"Shinto Shrine","b":"26E9","j":["religion","shinto","shrine","temple","japan","kyoto"]},"kaaba":{"a":"Kaaba","b":"1F54B","j":["islam","Muslim","religion","mecca","mosque"]},"fountain":{"a":"Fountain","b":"26F2","j":["photo","summer","water","fresh"]},"tent":{"a":"Tent","b":"26FA","j":["camping","photo","outdoors"]},"foggy":{"a":"Foggy","b":"1F301","j":["fog","photo","mountain"]},"night-with-stars":{"a":"Night with Stars","b":"1F303","j":["night","star","evening","city","downtown"]},"cityscape":{"a":"Cityscape","b":"1F3D9","j":["city","photo","night life","urban"]},"sunrise-over-mountains":{"a":"Sunrise over Mountains","b":"1F304","j":["morning","mountain","sun","sunrise","view","vacation","photo"]},"sunrise":{"a":"Sunrise","b":"1F305","j":["morning","sun","view","vacation","photo"]},"cityscape-at-dusk":{"a":"Cityscape at Dusk","b":"1F306","j":["city","dusk","evening","landscape","sunset","photo","sky","buildings"]},"sunset":{"a":"Sunset","b":"1F307","j":["dusk","sun","photo","good morning","dawn"]},"bridge-at-night":{"a":"Bridge at Night","b":"1F309","j":["bridge","night","photo","sanfrancisco"]},"hot-springs":{"a":"Hot Springs","b":"2668","j":["hot","hotsprings","springs","steaming","bath","warm","relax"]},"carousel-horse":{"a":"Carousel Horse","b":"1F3A0","j":["carousel","horse","photo","carnival"]},"playground-slide":{"a":"⊛ Playground Slide","b":"1F6DD","j":["amusement park","play"]},"ferris-wheel":{"a":"Ferris Wheel","b":"1F3A1","j":["amusement park","ferris","wheel","photo","carnival","londoneye"]},"roller-coaster":{"a":"Roller Coaster","b":"1F3A2","j":["amusement park","coaster","roller","carnival","playground","photo","fun"]},"barber-pole":{"a":"Barber Pole","b":"1F488","j":["barber","haircut","pole","hair","salon","style"]},"circus-tent":{"a":"Circus Tent","b":"1F3AA","j":["circus","tent","festival","carnival","party"]},"locomotive":{"a":"Locomotive","b":"1F682","j":["engine","railway","steam","train","transportation","vehicle"]},"railway-car":{"a":"Railway Car","b":"1F683","j":["car","electric","railway","train","tram","trolleybus","transportation","vehicle"]},"highspeed-train":{"a":"High-Speed Train","b":"1F684","j":["high-speed train","railway","shinkansen","speed","train","high_speed_train","transportation","vehicle"]},"bullet-train":{"a":"Bullet Train","b":"1F685","j":["bullet","railway","shinkansen","speed","train","transportation","vehicle","fast","public","travel"]},"train":{"a":"Train","b":"1F686","j":["railway","transportation","vehicle"]},"metro":{"a":"Metro","b":"1F687","j":["subway","transportation","blue-square","mrt","underground","tube"]},"light-rail":{"a":"Light Rail","b":"1F688","j":["railway","transportation","vehicle"]},"station":{"a":"Station","b":"1F689","j":["railway","train","transportation","vehicle","public"]},"tram":{"a":"Tram","b":"1F68A","j":["trolleybus","transportation","vehicle"]},"monorail":{"a":"Monorail","b":"1F69D","j":["vehicle","transportation"]},"mountain-railway":{"a":"Mountain Railway","b":"1F69E","j":["car","mountain","railway","transportation","vehicle"]},"tram-car":{"a":"Tram Car","b":"1F68B","j":["car","tram","trolleybus","transportation","vehicle","carriage","public","travel"]},"bus":{"a":"Bus","b":"1F68C","j":["vehicle","car","transportation"]},"oncoming-bus":{"a":"Oncoming Bus","b":"1F68D","j":["bus","oncoming","vehicle","transportation"]},"trolleybus":{"a":"Trolleybus","b":"1F68E","j":["bus","tram","trolley","bart","transportation","vehicle"]},"minibus":{"a":"Minibus","b":"1F690","j":["bus","vehicle","car","transportation"]},"ambulance":{"a":"Ambulance","b":"1F691","j":["vehicle","health","911","hospital"]},"fire-engine":{"a":"Fire Engine","b":"1F692","j":["engine","fire","truck","transportation","cars","vehicle"]},"police-car":{"a":"Police Car","b":"1F693","j":["car","patrol","police","vehicle","cars","transportation","law","legal","enforcement"]},"oncoming-police-car":{"a":"Oncoming Police Car","b":"1F694","j":["car","oncoming","police","vehicle","law","legal","enforcement","911"]},"taxi":{"a":"Taxi","b":"1F695","j":["vehicle","uber","cars","transportation"]},"oncoming-taxi":{"a":"Oncoming Taxi","b":"1F696","j":["oncoming","taxi","vehicle","cars","uber"]},"automobile":{"a":"Automobile","b":"1F697","j":["car","red","transportation","vehicle"]},"oncoming-automobile":{"a":"Oncoming Automobile","b":"1F698","j":["automobile","car","oncoming","vehicle","transportation"]},"sport-utility-vehicle":{"a":"Sport Utility Vehicle","b":"1F699","j":["recreational","sport utility","transportation","vehicle"]},"pickup-truck":{"a":"Pickup Truck","b":"1F6FB","j":["pick-up","pickup","truck","car","transportation"]},"delivery-truck":{"a":"Delivery Truck","b":"1F69A","j":["delivery","truck","cars","transportation"]},"articulated-lorry":{"a":"Articulated Lorry","b":"1F69B","j":["lorry","semi","truck","vehicle","cars","transportation","express"]},"tractor":{"a":"Tractor","b":"1F69C","j":["vehicle","car","farming","agriculture"]},"racing-car":{"a":"Racing Car","b":"1F3CE","j":["car","racing","sports","race","fast","formula","f1"]},"motorcycle":{"a":"Motorcycle","b":"1F3CD","j":["racing","race","sports","fast"]},"motor-scooter":{"a":"Motor Scooter","b":"1F6F5","j":["motor","scooter","vehicle","vespa","sasha"]},"manual-wheelchair":{"a":"Manual Wheelchair","b":"1F9BD","j":["accessibility"]},"motorized-wheelchair":{"a":"Motorized Wheelchair","b":"1F9BC","j":["accessibility"]},"auto-rickshaw":{"a":"Auto Rickshaw","b":"1F6FA","j":["tuk tuk","move","transportation"]},"bicycle":{"a":"Bicycle","b":"1F6B2","j":["bike","sports","exercise","hipster"]},"kick-scooter":{"a":"Kick Scooter","b":"1F6F4","j":["kick","scooter","vehicle","razor"]},"skateboard":{"a":"Skateboard","b":"1F6F9","j":["board"]},"roller-skate":{"a":"Roller Skate","b":"1F6FC","j":["roller","skate","footwear","sports"]},"bus-stop":{"a":"Bus Stop","b":"1F68F","j":["bus","stop","transportation","wait"]},"motorway":{"a":"Motorway","b":"1F6E3","j":["highway","road","cupertino","interstate"]},"railway-track":{"a":"Railway Track","b":"1F6E4","j":["railway","train","transportation"]},"oil-drum":{"a":"Oil Drum","b":"1F6E2","j":["drum","oil","barrell"]},"fuel-pump":{"a":"Fuel Pump","b":"26FD","j":["diesel","fuel","fuelpump","gas","pump","station","gas station","petroleum"]},"wheel":{"a":"⊛ Wheel","b":"1F6DE","j":["circle","tire","turn"]},"police-car-light":{"a":"Police Car Light","b":"1F6A8","j":["beacon","car","light","police","revolving","ambulance","911","emergency","alert","error","pinged","law","legal"]},"horizontal-traffic-light":{"a":"Horizontal Traffic Light","b":"1F6A5","j":["light","signal","traffic","transportation"]},"vertical-traffic-light":{"a":"Vertical Traffic Light","b":"1F6A6","j":["light","signal","traffic","transportation","driving"]},"stop-sign":{"a":"Stop Sign","b":"1F6D1","j":["octagonal","sign","stop"]},"construction":{"a":"Construction","b":"1F6A7","j":["barrier","wip","progress","caution","warning"]},"anchor":{"a":"Anchor","b":"2693","j":["ship","tool","ferry","sea","boat"]},"ring-buoy":{"a":"⊛ Ring Buoy","b":"1F6DF","j":["float","life preserver","life saver","rescue","safety"]},"sailboat":{"a":"Sailboat","b":"26F5","j":["boat","resort","sea","yacht","ship","summer","transportation","water","sailing"]},"canoe":{"a":"Canoe","b":"1F6F6","j":["boat","paddle","water","ship"]},"speedboat":{"a":"Speedboat","b":"1F6A4","j":["boat","ship","transportation","vehicle","summer"]},"passenger-ship":{"a":"Passenger Ship","b":"1F6F3","j":["passenger","ship","yacht","cruise","ferry"]},"ferry":{"a":"Ferry","b":"26F4","j":["boat","passenger","ship","yacht"]},"motor-boat":{"a":"Motor Boat","b":"1F6E5","j":["boat","motorboat","ship"]},"ship":{"a":"Ship","b":"1F6A2","j":["boat","passenger","transportation","titanic","deploy"]},"airplane":{"a":"Airplane","b":"2708","j":["aeroplane","vehicle","transportation","flight","fly"]},"small-airplane":{"a":"Small Airplane","b":"1F6E9","j":["aeroplane","airplane","flight","transportation","fly","vehicle"]},"airplane-departure":{"a":"Airplane Departure","b":"1F6EB","j":["aeroplane","airplane","check-in","departure","departures","airport","flight","landing"]},"airplane-arrival":{"a":"Airplane Arrival","b":"1F6EC","j":["aeroplane","airplane","arrivals","arriving","landing","airport","flight","boarding"]},"parachute":{"a":"Parachute","b":"1FA82","j":["hang-glide","parasail","skydive","fly","glide"]},"seat":{"a":"Seat","b":"1F4BA","j":["chair","sit","airplane","transport","bus","flight","fly"]},"helicopter":{"a":"Helicopter","b":"1F681","j":["vehicle","transportation","fly"]},"suspension-railway":{"a":"Suspension Railway","b":"1F69F","j":["railway","suspension","vehicle","transportation"]},"mountain-cableway":{"a":"Mountain Cableway","b":"1F6A0","j":["cable","gondola","mountain","transportation","vehicle","ski"]},"aerial-tramway":{"a":"Aerial Tramway","b":"1F6A1","j":["aerial","cable","car","gondola","tramway","transportation","vehicle","ski"]},"satellite":{"a":"Satellite","b":"1F6F0","j":["space","communication","gps","orbit","spaceflight","NASA","ISS"]},"rocket":{"a":"Rocket","b":"1F680","j":["space","launch","ship","staffmode","NASA","outer space","outer_space","fly"]},"flying-saucer":{"a":"Flying Saucer","b":"1F6F8","j":["UFO","transportation","vehicle","ufo"]},"bellhop-bell":{"a":"Bellhop Bell","b":"1F6CE","j":["bell","bellhop","hotel","service"]},"luggage":{"a":"Luggage","b":"1F9F3","j":["packing","travel"]},"hourglass-done":{"a":"Hourglass Done","b":"231B","j":["sand","timer","time","clock","oldschool","limit","exam","quiz","test"]},"hourglass-not-done":{"a":"Hourglass Not Done","b":"23F3","j":["hourglass","sand","timer","oldschool","time","countdown"]},"watch":{"a":"Watch","b":"231A","j":["clock","time","accessories"]},"alarm-clock":{"a":"Alarm Clock","b":"23F0","j":["alarm","clock","time","wake"]},"stopwatch":{"a":"Stopwatch","b":"23F1","j":["clock","time","deadline"]},"timer-clock":{"a":"Timer Clock","b":"23F2","j":["clock","timer","alarm"]},"mantelpiece-clock":{"a":"Mantelpiece Clock","b":"1F570","j":["clock","time"]},"twelve-oclock":{"a":"Twelve O’Clock","b":"1F55B","j":["00","12","12:00","clock","o’clock","twelve","twelve_o_clock","time","noon","midnight","midday","late","early","schedule"]},"twelvethirty":{"a":"Twelve-Thirty","b":"1F567","j":["12","12:30","clock","thirty","twelve","twelve-thirty","twelve_thirty","time","late","early","schedule"]},"one-oclock":{"a":"One O’Clock","b":"1F550","j":["00","1","1:00","clock","o’clock","one","one_o_clock","time","late","early","schedule"]},"onethirty":{"a":"One-Thirty","b":"1F55C","j":["1","1:30","clock","one","one-thirty","thirty","one_thirty","time","late","early","schedule"]},"two-oclock":{"a":"Two O’Clock","b":"1F551","j":["00","2","2:00","clock","o’clock","two","two_o_clock","time","late","early","schedule"]},"twothirty":{"a":"Two-Thirty","b":"1F55D","j":["2","2:30","clock","thirty","two","two-thirty","two_thirty","time","late","early","schedule"]},"three-oclock":{"a":"Three O’Clock","b":"1F552","j":["00","3","3:00","clock","o’clock","three","three_o_clock","time","late","early","schedule"]},"threethirty":{"a":"Three-Thirty","b":"1F55E","j":["3","3:30","clock","thirty","three","three-thirty","three_thirty","time","late","early","schedule"]},"four-oclock":{"a":"Four O’Clock","b":"1F553","j":["00","4","4:00","clock","four","o’clock","four_o_clock","time","late","early","schedule"]},"fourthirty":{"a":"Four-Thirty","b":"1F55F","j":["4","4:30","clock","four","four-thirty","thirty","four_thirty","time","late","early","schedule"]},"five-oclock":{"a":"Five O’Clock","b":"1F554","j":["00","5","5:00","clock","five","o’clock","five_o_clock","time","late","early","schedule"]},"fivethirty":{"a":"Five-Thirty","b":"1F560","j":["5","5:30","clock","five","five-thirty","thirty","five_thirty","time","late","early","schedule"]},"six-oclock":{"a":"Six O’Clock","b":"1F555","j":["00","6","6:00","clock","o’clock","six","six_o_clock","time","late","early","schedule","dawn","dusk"]},"sixthirty":{"a":"Six-Thirty","b":"1F561","j":["6","6:30","clock","six","six-thirty","thirty","six_thirty","time","late","early","schedule"]},"seven-oclock":{"a":"Seven O’Clock","b":"1F556","j":["00","7","7:00","clock","o’clock","seven","seven_o_clock","time","late","early","schedule"]},"seventhirty":{"a":"Seven-Thirty","b":"1F562","j":["7","7:30","clock","seven","seven-thirty","thirty","seven_thirty","time","late","early","schedule"]},"eight-oclock":{"a":"Eight O’Clock","b":"1F557","j":["00","8","8:00","clock","eight","o’clock","eight_o_clock","time","late","early","schedule"]},"eightthirty":{"a":"Eight-Thirty","b":"1F563","j":["8","8:30","clock","eight","eight-thirty","thirty","eight_thirty","time","late","early","schedule"]},"nine-oclock":{"a":"Nine O’Clock","b":"1F558","j":["00","9","9:00","clock","nine","o’clock","nine_o_clock","time","late","early","schedule"]},"ninethirty":{"a":"Nine-Thirty","b":"1F564","j":["9","9:30","clock","nine","nine-thirty","thirty","nine_thirty","time","late","early","schedule"]},"ten-oclock":{"a":"Ten O’Clock","b":"1F559","j":["00","10","10:00","clock","o’clock","ten","ten_o_clock","time","late","early","schedule"]},"tenthirty":{"a":"Ten-Thirty","b":"1F565","j":["10","10:30","clock","ten","ten-thirty","thirty","ten_thirty","time","late","early","schedule"]},"eleven-oclock":{"a":"Eleven O’Clock","b":"1F55A","j":["00","11","11:00","clock","eleven","o’clock","eleven_o_clock","time","late","early","schedule"]},"eleventhirty":{"a":"Eleven-Thirty","b":"1F566","j":["11","11:30","clock","eleven","eleven-thirty","thirty","eleven_thirty","time","late","early","schedule"]},"new-moon":{"a":"New Moon","b":"1F311","j":["dark","moon","nature","twilight","planet","space","night","evening","sleep"]},"waxing-crescent-moon":{"a":"Waxing Crescent Moon","b":"1F312","j":["crescent","moon","waxing","nature","twilight","planet","space","night","evening","sleep"]},"first-quarter-moon":{"a":"First Quarter Moon","b":"1F313","j":["moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"waxing-gibbous-moon":{"a":"Waxing Gibbous Moon","b":"1F314","j":["gibbous","moon","waxing","nature","night","sky","gray","twilight","planet","space","evening","sleep"]},"full-moon":{"a":"Full Moon","b":"1F315","j":["full","moon","nature","yellow","twilight","planet","space","night","evening","sleep"]},"waning-gibbous-moon":{"a":"Waning Gibbous Moon","b":"1F316","j":["gibbous","moon","waning","nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"]},"last-quarter-moon":{"a":"Last Quarter Moon","b":"1F317","j":["moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"waning-crescent-moon":{"a":"Waning Crescent Moon","b":"1F318","j":["crescent","moon","waning","nature","twilight","planet","space","night","evening","sleep"]},"crescent-moon":{"a":"Crescent Moon","b":"1F319","j":["crescent","moon","night","sleep","sky","evening","magic"]},"new-moon-face":{"a":"New Moon Face","b":"1F31A","j":["face","moon","nature","twilight","planet","space","night","evening","sleep"]},"first-quarter-moon-face":{"a":"First Quarter Moon Face","b":"1F31B","j":["face","moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"last-quarter-moon-face":{"a":"Last Quarter Moon Face","b":"1F31C","j":["face","moon","quarter","nature","twilight","planet","space","night","evening","sleep"]},"thermometer":{"a":"Thermometer","b":"1F321","j":["weather","temperature","hot","cold"]},"sun":{"a":"Sun","b":"2600","j":["bright","rays","sunny","weather","nature","brightness","summer","beach","spring"]},"full-moon-face":{"a":"Full Moon Face","b":"1F31D","j":["bright","face","full","moon","nature","twilight","planet","space","night","evening","sleep"]},"sun-with-face":{"a":"Sun with Face","b":"1F31E","j":["bright","face","sun","nature","morning","sky"]},"ringed-planet":{"a":"Ringed Planet","b":"1FA90","j":["saturn","saturnine","outerspace"]},"star":{"a":"Star","b":"2B50","j":["night","yellow"]},"glowing-star":{"a":"Glowing Star","b":"1F31F","j":["glittery","glow","shining","sparkle","star","night","awesome","good","magic"]},"shooting-star":{"a":"Shooting Star","b":"1F320","j":["falling","shooting","star","night","photo"]},"milky-way":{"a":"Milky Way","b":"1F30C","j":["space","photo","stars"]},"cloud":{"a":"Cloud","b":"2601","j":["weather","sky"]},"sun-behind-cloud":{"a":"Sun Behind Cloud","b":"26C5","j":["cloud","sun","weather","nature","cloudy","morning","fall","spring"]},"cloud-with-lightning-and-rain":{"a":"Cloud with Lightning and Rain","b":"26C8","j":["cloud","rain","thunder","weather","lightning"]},"sun-behind-small-cloud":{"a":"Sun Behind Small Cloud","b":"1F324","j":["cloud","sun","weather"]},"sun-behind-large-cloud":{"a":"Sun Behind Large Cloud","b":"1F325","j":["cloud","sun","weather"]},"sun-behind-rain-cloud":{"a":"Sun Behind Rain Cloud","b":"1F326","j":["cloud","rain","sun","weather"]},"cloud-with-rain":{"a":"Cloud with Rain","b":"1F327","j":["cloud","rain","weather"]},"cloud-with-snow":{"a":"Cloud with Snow","b":"1F328","j":["cloud","cold","snow","weather"]},"cloud-with-lightning":{"a":"Cloud with Lightning","b":"1F329","j":["cloud","lightning","weather","thunder"]},"tornado":{"a":"Tornado","b":"1F32A","j":["cloud","whirlwind","weather","cyclone","twister"]},"fog":{"a":"Fog","b":"1F32B","j":["cloud","weather"]},"wind-face":{"a":"Wind Face","b":"1F32C","j":["blow","cloud","face","wind","gust","air"]},"cyclone":{"a":"Cyclone","b":"1F300","j":["dizzy","hurricane","twister","typhoon","weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado"]},"rainbow":{"a":"Rainbow","b":"1F308","j":["rain","nature","happy","unicorn_face","photo","sky","spring"]},"closed-umbrella":{"a":"Closed Umbrella","b":"1F302","j":["clothing","rain","umbrella","weather","drizzle"]},"umbrella":{"a":"Umbrella","b":"2602","j":["clothing","rain","weather","spring"]},"umbrella-with-rain-drops":{"a":"Umbrella with Rain Drops","b":"2614","j":["clothing","drop","rain","umbrella","rainy","weather","spring"]},"umbrella-on-ground":{"a":"Umbrella on Ground","b":"26F1","j":["rain","sun","umbrella","weather","summer"]},"high-voltage":{"a":"High Voltage","b":"26A1","j":["danger","electric","lightning","voltage","zap","thunder","weather","lightning bolt","fast"]},"snowflake":{"a":"Snowflake","b":"2744","j":["cold","snow","winter","season","weather","christmas","xmas"]},"snowman":{"a":"Snowman","b":"2603","j":["cold","snow","winter","season","weather","christmas","xmas","frozen"]},"snowman-without-snow":{"a":"Snowman Without Snow","b":"26C4","j":["cold","snow","snowman","winter","season","weather","christmas","xmas","frozen","without_snow"]},"comet":{"a":"Comet","b":"2604","j":["space"]},"fire":{"a":"Fire","b":"1F525","j":["flame","tool","hot","cook"]},"droplet":{"a":"Droplet","b":"1F4A7","j":["cold","comic","drop","sweat","water","drip","faucet","spring"]},"water-wave":{"a":"Water Wave","b":"1F30A","j":["ocean","water","wave","sea","nature","tsunami","disaster"]},"jackolantern":{"a":"Jack-O-Lantern","b":"1F383","j":["celebration","halloween","jack","jack-o-lantern","lantern","jack_o_lantern","light","pumpkin","creepy","fall"]},"christmas-tree":{"a":"Christmas Tree","b":"1F384","j":["celebration","Christmas","tree","festival","vacation","december","xmas"]},"fireworks":{"a":"Fireworks","b":"1F386","j":["celebration","photo","festival","carnival","congratulations"]},"sparkler":{"a":"Sparkler","b":"1F387","j":["celebration","fireworks","sparkle","stars","night","shine"]},"firecracker":{"a":"Firecracker","b":"1F9E8","j":["dynamite","explosive","fireworks","boom","explode","explosion"]},"sparkles":{"a":"Sparkles","b":"2728","j":["*","sparkle","star","stars","shine","shiny","cool","awesome","good","magic"]},"balloon":{"a":"Balloon","b":"1F388","j":["celebration","party","birthday","circus"]},"party-popper":{"a":"Party Popper","b":"1F389","j":["celebration","party","popper","tada","congratulations","birthday","magic","circus"]},"confetti-ball":{"a":"Confetti Ball","b":"1F38A","j":["ball","celebration","confetti","festival","party","birthday","circus"]},"tanabata-tree":{"a":"Tanabata Tree","b":"1F38B","j":["banner","celebration","Japanese","tree","plant","nature","branch","summer"]},"pine-decoration":{"a":"Pine Decoration","b":"1F38D","j":["bamboo","celebration","Japanese","pine","plant","nature","vegetable","panda"]},"japanese-dolls":{"a":"Japanese Dolls","b":"1F38E","j":["celebration","doll","festival","Japanese","Japanese dolls","japanese","toy","kimono"]},"carp-streamer":{"a":"Carp Streamer","b":"1F38F","j":["carp","celebration","streamer","fish","japanese","koinobori","banner"]},"wind-chime":{"a":"Wind Chime","b":"1F390","j":["bell","celebration","chime","wind","nature","ding","spring"]},"moon-viewing-ceremony":{"a":"Moon Viewing Ceremony","b":"1F391","j":["celebration","ceremony","moon","photo","japan","asia","tsukimi"]},"red-envelope":{"a":"Red Envelope","b":"1F9E7","j":["gift","good luck","hóngbāo","lai see","money"]},"ribbon":{"a":"Ribbon","b":"1F380","j":["celebration","decoration","pink","girl","bowtie"]},"wrapped-gift":{"a":"Wrapped Gift","b":"1F381","j":["box","celebration","gift","present","wrapped","birthday","christmas","xmas"]},"reminder-ribbon":{"a":"Reminder Ribbon","b":"1F397","j":["celebration","reminder","ribbon","sports","cause","support","awareness"]},"admission-tickets":{"a":"Admission Tickets","b":"1F39F","j":["admission","ticket","sports","concert","entrance"]},"ticket":{"a":"Ticket","b":"1F3AB","j":["admission","event","concert","pass"]},"military-medal":{"a":"Military Medal","b":"1F396","j":["celebration","medal","military","award","winning","army"]},"trophy":{"a":"Trophy","b":"1F3C6","j":["prize","win","award","contest","place","ftw","ceremony"]},"sports-medal":{"a":"Sports Medal","b":"1F3C5","j":["medal","award","winning"]},"1st-place-medal":{"a":"1st Place Medal","b":"1F947","j":["first","gold","medal","award","winning"]},"2nd-place-medal":{"a":"2nd Place Medal","b":"1F948","j":["medal","second","silver","award"]},"3rd-place-medal":{"a":"3rd Place Medal","b":"1F949","j":["bronze","medal","third","award"]},"soccer-ball":{"a":"Soccer Ball","b":"26BD","j":["ball","football","soccer","sports"]},"baseball":{"a":"Baseball","b":"26BE","j":["ball","sports","balls"]},"softball":{"a":"Softball","b":"1F94E","j":["ball","glove","underarm","sports","balls"]},"basketball":{"a":"Basketball","b":"1F3C0","j":["ball","hoop","sports","balls","NBA"]},"volleyball":{"a":"Volleyball","b":"1F3D0","j":["ball","game","sports","balls"]},"american-football":{"a":"American Football","b":"1F3C8","j":["american","ball","football","sports","balls","NFL"]},"rugby-football":{"a":"Rugby Football","b":"1F3C9","j":["ball","football","rugby","sports","team"]},"tennis":{"a":"Tennis","b":"1F3BE","j":["ball","racquet","sports","balls","green"]},"flying-disc":{"a":"Flying Disc","b":"1F94F","j":["ultimate","sports","frisbee"]},"bowling":{"a":"Bowling","b":"1F3B3","j":["ball","game","sports","fun","play"]},"cricket-game":{"a":"Cricket Game","b":"1F3CF","j":["ball","bat","game","sports"]},"field-hockey":{"a":"Field Hockey","b":"1F3D1","j":["ball","field","game","hockey","stick","sports"]},"ice-hockey":{"a":"Ice Hockey","b":"1F3D2","j":["game","hockey","ice","puck","stick","sports"]},"lacrosse":{"a":"Lacrosse","b":"1F94D","j":["ball","goal","stick","sports"]},"ping-pong":{"a":"Ping Pong","b":"1F3D3","j":["ball","bat","game","paddle","table tennis","sports","pingpong"]},"badminton":{"a":"Badminton","b":"1F3F8","j":["birdie","game","racquet","shuttlecock","sports"]},"boxing-glove":{"a":"Boxing Glove","b":"1F94A","j":["boxing","glove","sports","fighting"]},"martial-arts-uniform":{"a":"Martial Arts Uniform","b":"1F94B","j":["judo","karate","martial arts","taekwondo","uniform"]},"goal-net":{"a":"Goal Net","b":"1F945","j":["goal","net","sports"]},"flag-in-hole":{"a":"Flag in Hole","b":"26F3","j":["golf","hole","sports","business","flag","summer"]},"ice-skate":{"a":"Ice Skate","b":"26F8","j":["ice","skate","sports"]},"fishing-pole":{"a":"Fishing Pole","b":"1F3A3","j":["fish","pole","food","hobby","summer"]},"diving-mask":{"a":"Diving Mask","b":"1F93F","j":["diving","scuba","snorkeling","sport","ocean"]},"running-shirt":{"a":"Running Shirt","b":"1F3BD","j":["athletics","running","sash","shirt","play","pageant"]},"skis":{"a":"Skis","b":"1F3BF","j":["ski","snow","sports","winter","cold"]},"sled":{"a":"Sled","b":"1F6F7","j":["sledge","sleigh","luge","toboggan"]},"curling-stone":{"a":"Curling Stone","b":"1F94C","j":["game","rock","sports"]},"bullseye":{"a":"Bullseye","b":"1F3AF","j":["dart","direct hit","game","hit","target","direct_hit","play","bar"]},"yoyo":{"a":"Yo-Yo","b":"1FA80","j":["fluctuate","toy","yo-yo","yo_yo"]},"kite":{"a":"Kite","b":"1FA81","j":["fly","soar","wind"]},"pool-8-ball":{"a":"Pool 8 Ball","b":"1F3B1","j":["8","ball","billiard","eight","game","pool","hobby","luck","magic"]},"crystal-ball":{"a":"Crystal Ball","b":"1F52E","j":["ball","crystal","fairy tale","fantasy","fortune","tool","disco","party","magic","circus","fortune_teller"]},"magic-wand":{"a":"Magic Wand","b":"1FA84","j":["magic","witch","wizard","supernature","power"]},"nazar-amulet":{"a":"Nazar Amulet","b":"1F9FF","j":["bead","charm","evil-eye","nazar","talisman"]},"hamsa":{"a":"⊛ Hamsa","b":"1FAAC","j":["amulet","Fatima","hand","Mary","Miriam","protection"]},"video-game":{"a":"Video Game","b":"1F3AE","j":["controller","game","play","console","PS4"]},"joystick":{"a":"Joystick","b":"1F579","j":["game","video game","play"]},"slot-machine":{"a":"Slot Machine","b":"1F3B0","j":["game","slot","bet","gamble","vegas","fruit machine","luck","casino"]},"game-die":{"a":"Game Die","b":"1F3B2","j":["dice","die","game","random","tabletop","play","luck"]},"puzzle-piece":{"a":"Puzzle Piece","b":"1F9E9","j":["clue","interlocking","jigsaw","piece","puzzle"]},"teddy-bear":{"a":"Teddy Bear","b":"1F9F8","j":["plaything","plush","stuffed","toy"]},"piata":{"a":"Piñata","b":"1FA85","j":["celebration","party","piñata","pinata","mexico","candy"]},"mirror-ball":{"a":"⊛ Mirror Ball","b":"1FAA9","j":["dance","disco","glitter","party"]},"nesting-dolls":{"a":"Nesting Dolls","b":"1FA86","j":["doll","nesting","russia","matryoshka","toy"]},"spade-suit":{"a":"Spade Suit","b":"2660","j":["card","game","poker","cards","suits","magic"]},"heart-suit":{"a":"Heart Suit","b":"2665","j":["card","game","poker","cards","magic","suits"]},"diamond-suit":{"a":"Diamond Suit","b":"2666","j":["card","game","poker","cards","magic","suits"]},"club-suit":{"a":"Club Suit","b":"2663","j":["card","game","poker","cards","magic","suits"]},"chess-pawn":{"a":"Chess Pawn","b":"265F","j":["chess","dupe","expendable"]},"joker":{"a":"Joker","b":"1F0CF","j":["card","game","wildcard","poker","cards","play","magic"]},"mahjong-red-dragon":{"a":"Mahjong Red Dragon","b":"1F004","j":["game","mahjong","red","play","chinese","kanji"]},"flower-playing-cards":{"a":"Flower Playing Cards","b":"1F3B4","j":["card","flower","game","Japanese","playing","sunset","red"]},"performing-arts":{"a":"Performing Arts","b":"1F3AD","j":["art","mask","performing","theater","theatre","acting","drama"]},"framed-picture":{"a":"Framed Picture","b":"1F5BC","j":["art","frame","museum","painting","picture","photography"]},"artist-palette":{"a":"Artist Palette","b":"1F3A8","j":["art","museum","painting","palette","design","paint","draw","colors"]},"thread":{"a":"Thread","b":"1F9F5","j":["needle","sewing","spool","string"]},"sewing-needle":{"a":"Sewing Needle","b":"1FAA1","j":["embroidery","needle","sewing","stitches","sutures","tailoring"]},"yarn":{"a":"Yarn","b":"1F9F6","j":["ball","crochet","knit"]},"knot":{"a":"Knot","b":"1FAA2","j":["rope","tangled","tie","twine","twist","scout"]},"glasses":{"a":"Glasses","b":"1F453","j":["clothing","eye","eyeglasses","eyewear","fashion","accessories","eyesight","nerdy","dork","geek"]},"sunglasses":{"a":"Sunglasses","b":"1F576","j":["dark","eye","eyewear","glasses","face","cool","accessories"]},"goggles":{"a":"Goggles","b":"1F97D","j":["eye protection","swimming","welding","eyes","protection","safety"]},"lab-coat":{"a":"Lab Coat","b":"1F97C","j":["doctor","experiment","scientist","chemist"]},"safety-vest":{"a":"Safety Vest","b":"1F9BA","j":["emergency","safety","vest","protection"]},"necktie":{"a":"Necktie","b":"1F454","j":["clothing","tie","shirt","suitup","formal","fashion","cloth","business"]},"tshirt":{"a":"T-Shirt","b":"1F455","j":["clothing","shirt","t-shirt","t_shirt","fashion","cloth","casual","tee"]},"jeans":{"a":"Jeans","b":"1F456","j":["clothing","pants","trousers","fashion","shopping"]},"scarf":{"a":"Scarf","b":"1F9E3","j":["neck","winter","clothes"]},"gloves":{"a":"Gloves","b":"1F9E4","j":["hand","hands","winter","clothes"]},"coat":{"a":"Coat","b":"1F9E5","j":["jacket"]},"socks":{"a":"Socks","b":"1F9E6","j":["stocking","stockings","clothes"]},"dress":{"a":"Dress","b":"1F457","j":["clothing","clothes","fashion","shopping"]},"kimono":{"a":"Kimono","b":"1F458","j":["clothing","dress","fashion","women","female","japanese"]},"sari":{"a":"Sari","b":"1F97B","j":["clothing","dress"]},"onepiece-swimsuit":{"a":"One-Piece Swimsuit","b":"1FA71","j":["bathing suit","one-piece swimsuit","one_piece_swimsuit","fashion"]},"briefs":{"a":"Briefs","b":"1FA72","j":["bathing suit","one-piece","swimsuit","underwear","clothing"]},"shorts":{"a":"Shorts","b":"1FA73","j":["bathing suit","pants","underwear","clothing"]},"bikini":{"a":"Bikini","b":"1F459","j":["clothing","swim","swimming","female","woman","girl","fashion","beach","summer"]},"womans-clothes":{"a":"Woman’S Clothes","b":"1F45A","j":["clothing","woman","woman’s clothes","woman_s_clothes","fashion","shopping_bags","female"]},"purse":{"a":"Purse","b":"1F45B","j":["clothing","coin","fashion","accessories","money","sales","shopping"]},"handbag":{"a":"Handbag","b":"1F45C","j":["bag","clothing","purse","fashion","accessory","accessories","shopping"]},"clutch-bag":{"a":"Clutch Bag","b":"1F45D","j":["bag","clothing","pouch","accessories","shopping"]},"shopping-bags":{"a":"Shopping Bags","b":"1F6CD","j":["bag","hotel","shopping","mall","buy","purchase"]},"backpack":{"a":"Backpack","b":"1F392","j":["bag","rucksack","satchel","school","student","education"]},"thong-sandal":{"a":"Thong Sandal","b":"1FA74","j":["beach sandals","sandals","thong sandals","thongs","zōri","footwear","summer"]},"mans-shoe":{"a":"Man’S Shoe","b":"1F45E","j":["clothing","man","man’s shoe","shoe","man_s_shoe","fashion","male"]},"running-shoe":{"a":"Running Shoe","b":"1F45F","j":["athletic","clothing","shoe","sneaker","shoes","sports","sneakers"]},"hiking-boot":{"a":"Hiking Boot","b":"1F97E","j":["backpacking","boot","camping","hiking"]},"flat-shoe":{"a":"Flat Shoe","b":"1F97F","j":["ballet flat","slip-on","slipper","ballet"]},"highheeled-shoe":{"a":"High-Heeled Shoe","b":"1F460","j":["clothing","heel","high-heeled shoe","shoe","woman","high_heeled_shoe","fashion","shoes","female","pumps","stiletto"]},"womans-sandal":{"a":"Woman’S Sandal","b":"1F461","j":["clothing","sandal","shoe","woman","woman’s sandal","woman_s_sandal","shoes","fashion","flip flops"]},"ballet-shoes":{"a":"Ballet Shoes","b":"1FA70","j":["ballet","dance"]},"womans-boot":{"a":"Woman’S Boot","b":"1F462","j":["boot","clothing","shoe","woman","woman’s boot","woman_s_boot","shoes","fashion"]},"crown":{"a":"Crown","b":"1F451","j":["clothing","king","queen","kod","leader","royalty","lord"]},"womans-hat":{"a":"Woman’S Hat","b":"1F452","j":["clothing","hat","woman","woman’s hat","woman_s_hat","fashion","accessories","female","lady","spring"]},"top-hat":{"a":"Top Hat","b":"1F3A9","j":["clothing","hat","top","tophat","magic","gentleman","classy","circus"]},"graduation-cap":{"a":"Graduation Cap","b":"1F393","j":["cap","celebration","clothing","graduation","hat","school","college","degree","university","legal","learn","education"]},"billed-cap":{"a":"Billed Cap","b":"1F9E2","j":["baseball cap","cap","baseball"]},"military-helmet":{"a":"Military Helmet","b":"1FA96","j":["army","helmet","military","soldier","warrior","protection"]},"rescue-workers-helmet":{"a":"Rescue Worker’S Helmet","b":"26D1","j":["aid","cross","face","hat","helmet","rescue worker’s helmet","rescue_worker_s_helmet","construction","build"]},"prayer-beads":{"a":"Prayer Beads","b":"1F4FF","j":["beads","clothing","necklace","prayer","religion","dhikr","religious"]},"lipstick":{"a":"Lipstick","b":"1F484","j":["cosmetics","makeup","female","girl","fashion","woman"]},"ring":{"a":"Ring","b":"1F48D","j":["diamond","wedding","propose","marriage","valentines","fashion","jewelry","gem","engagement"]},"gem-stone":{"a":"Gem Stone","b":"1F48E","j":["diamond","gem","jewel","blue","ruby","jewelry"]},"muted-speaker":{"a":"Muted Speaker","b":"1F507","j":["mute","quiet","silent","speaker","sound","volume","silence"]},"speaker-low-volume":{"a":"Speaker Low Volume","b":"1F508","j":["soft","sound","volume","silence","broadcast"]},"speaker-medium-volume":{"a":"Speaker Medium Volume","b":"1F509","j":["medium","volume","speaker","broadcast"]},"speaker-high-volume":{"a":"Speaker High Volume","b":"1F50A","j":["loud","volume","noise","noisy","speaker","broadcast"]},"loudspeaker":{"a":"Loudspeaker","b":"1F4E2","j":["loud","public address","volume","sound"]},"megaphone":{"a":"Megaphone","b":"1F4E3","j":["cheering","sound","speaker","volume"]},"postal-horn":{"a":"Postal Horn","b":"1F4EF","j":["horn","post","postal","instrument","music"]},"bell":{"a":"Bell","b":"1F514","j":["sound","notification","christmas","xmas","chime"]},"bell-with-slash":{"a":"Bell with Slash","b":"1F515","j":["bell","forbidden","mute","quiet","silent","sound","volume"]},"musical-score":{"a":"Musical Score","b":"1F3BC","j":["music","score","treble","clef","compose"]},"musical-note":{"a":"Musical Note","b":"1F3B5","j":["music","note","score","tone","sound"]},"musical-notes":{"a":"Musical Notes","b":"1F3B6","j":["music","note","notes","score"]},"studio-microphone":{"a":"Studio Microphone","b":"1F399","j":["mic","microphone","music","studio","sing","recording","artist","talkshow"]},"level-slider":{"a":"Level Slider","b":"1F39A","j":["level","music","slider","scale"]},"control-knobs":{"a":"Control Knobs","b":"1F39B","j":["control","knobs","music","dial"]},"microphone":{"a":"Microphone","b":"1F3A4","j":["karaoke","mic","sound","music","PA","sing","talkshow"]},"headphone":{"a":"Headphone","b":"1F3A7","j":["earbud","music","score","gadgets"]},"radio":{"a":"Radio","b":"1F4FB","j":["video","communication","music","podcast","program"]},"saxophone":{"a":"Saxophone","b":"1F3B7","j":["instrument","music","sax","jazz","blues"]},"accordion":{"a":"Accordion","b":"1FA97","j":["concertina","squeeze box","music"]},"guitar":{"a":"Guitar","b":"1F3B8","j":["instrument","music"]},"musical-keyboard":{"a":"Musical Keyboard","b":"1F3B9","j":["instrument","keyboard","music","piano","compose"]},"trumpet":{"a":"Trumpet","b":"1F3BA","j":["instrument","music","brass"]},"violin":{"a":"Violin","b":"1F3BB","j":["instrument","music","orchestra","symphony"]},"banjo":{"a":"Banjo","b":"1FA95","j":["music","stringed","instructment"]},"drum":{"a":"Drum","b":"1F941","j":["drumsticks","music","instrument","snare"]},"long-drum":{"a":"Long Drum","b":"1FA98","j":["beat","conga","drum","rhythm","music"]},"mobile-phone":{"a":"Mobile Phone","b":"1F4F1","j":["cell","mobile","phone","telephone","technology","apple","gadgets","dial"]},"mobile-phone-with-arrow":{"a":"Mobile Phone with Arrow","b":"1F4F2","j":["arrow","cell","mobile","phone","receive","iphone","incoming"]},"telephone":{"a":"Telephone","b":"260E","j":["phone","technology","communication","dial"]},"telephone-receiver":{"a":"Telephone Receiver","b":"1F4DE","j":["phone","receiver","telephone","technology","communication","dial"]},"pager":{"a":"Pager","b":"1F4DF","j":["bbcall","oldschool","90s"]},"fax-machine":{"a":"Fax Machine","b":"1F4E0","j":["fax","communication","technology"]},"battery":{"a":"Battery","b":"1F50B","j":["power","energy","sustain"]},"low-battery":{"a":"⊛ Low Battery","b":"1FAAB","j":["electronic","low energy"]},"electric-plug":{"a":"Electric Plug","b":"1F50C","j":["electric","electricity","plug","charger","power"]},"laptop":{"a":"Laptop","b":"1F4BB","j":["computer","pc","personal","technology","screen","display","monitor"]},"desktop-computer":{"a":"Desktop Computer","b":"1F5A5","j":["computer","desktop","technology","computing","screen"]},"printer":{"a":"Printer","b":"1F5A8","j":["computer","paper","ink"]},"keyboard":{"a":"Keyboard","b":"2328","j":["computer","technology","type","input","text"]},"computer-mouse":{"a":"Computer Mouse","b":"1F5B1","j":["computer","click"]},"trackball":{"a":"Trackball","b":"1F5B2","j":["computer","technology","trackpad"]},"computer-disk":{"a":"Computer Disk","b":"1F4BD","j":["computer","disk","minidisk","optical","technology","record","data","90s"]},"floppy-disk":{"a":"Floppy Disk","b":"1F4BE","j":["computer","disk","floppy","oldschool","technology","save","90s","80s"]},"optical-disk":{"a":"Optical Disk","b":"1F4BF","j":["cd","computer","disk","optical","technology","dvd","disc","90s"]},"dvd":{"a":"Dvd","b":"1F4C0","j":["blu-ray","computer","disk","optical","cd","disc"]},"abacus":{"a":"Abacus","b":"1F9EE","j":["calculation"]},"movie-camera":{"a":"Movie Camera","b":"1F3A5","j":["camera","cinema","movie","film","record"]},"film-frames":{"a":"Film Frames","b":"1F39E","j":["cinema","film","frames","movie"]},"film-projector":{"a":"Film Projector","b":"1F4FD","j":["cinema","film","movie","projector","video","tape","record"]},"clapper-board":{"a":"Clapper Board","b":"1F3AC","j":["clapper","movie","film","record"]},"television":{"a":"Television","b":"1F4FA","j":["tv","video","technology","program","oldschool","show"]},"camera":{"a":"Camera","b":"1F4F7","j":["video","gadgets","photography"]},"camera-with-flash":{"a":"Camera with Flash","b":"1F4F8","j":["camera","flash","video","photography","gadgets"]},"video-camera":{"a":"Video Camera","b":"1F4F9","j":["camera","video","film","record"]},"videocassette":{"a":"Videocassette","b":"1F4FC","j":["tape","vhs","video","record","oldschool","90s","80s"]},"magnifying-glass-tilted-left":{"a":"Magnifying Glass Tilted Left","b":"1F50D","j":["glass","magnifying","search","tool","zoom","find","detective"]},"magnifying-glass-tilted-right":{"a":"Magnifying Glass Tilted Right","b":"1F50E","j":["glass","magnifying","search","tool","zoom","find","detective"]},"candle":{"a":"Candle","b":"1F56F","j":["light","fire","wax"]},"light-bulb":{"a":"Light Bulb","b":"1F4A1","j":["bulb","comic","electric","idea","light","electricity"]},"flashlight":{"a":"Flashlight","b":"1F526","j":["electric","light","tool","torch","dark","camping","sight","night"]},"red-paper-lantern":{"a":"Red Paper Lantern","b":"1F3EE","j":["bar","lantern","light","red","paper","halloween","spooky"]},"diya-lamp":{"a":"Diya Lamp","b":"1FA94","j":["diya","lamp","oil","lighting"]},"notebook-with-decorative-cover":{"a":"Notebook with Decorative Cover","b":"1F4D4","j":["book","cover","decorated","notebook","classroom","notes","record","paper","study"]},"closed-book":{"a":"Closed Book","b":"1F4D5","j":["book","closed","read","library","knowledge","textbook","learn"]},"open-book":{"a":"Open Book","b":"1F4D6","j":["book","open","read","library","knowledge","literature","learn","study"]},"green-book":{"a":"Green Book","b":"1F4D7","j":["book","green","read","library","knowledge","study"]},"blue-book":{"a":"Blue Book","b":"1F4D8","j":["blue","book","read","library","knowledge","learn","study"]},"orange-book":{"a":"Orange Book","b":"1F4D9","j":["book","orange","read","library","knowledge","textbook","study"]},"books":{"a":"Books","b":"1F4DA","j":["book","literature","library","study"]},"notebook":{"a":"Notebook","b":"1F4D3","j":["stationery","record","notes","paper","study"]},"ledger":{"a":"Ledger","b":"1F4D2","j":["notebook","notes","paper"]},"page-with-curl":{"a":"Page with Curl","b":"1F4C3","j":["curl","document","page","documents","office","paper"]},"scroll":{"a":"Scroll","b":"1F4DC","j":["paper","documents","ancient","history"]},"page-facing-up":{"a":"Page Facing Up","b":"1F4C4","j":["document","page","documents","office","paper","information"]},"newspaper":{"a":"Newspaper","b":"1F4F0","j":["news","paper","press","headline"]},"rolledup-newspaper":{"a":"Rolled-Up Newspaper","b":"1F5DE","j":["news","newspaper","paper","rolled","rolled-up newspaper","rolled_up_newspaper","press","headline"]},"bookmark-tabs":{"a":"Bookmark Tabs","b":"1F4D1","j":["bookmark","mark","marker","tabs","favorite","save","order","tidy"]},"bookmark":{"a":"Bookmark","b":"1F516","j":["mark","favorite","label","save"]},"label":{"a":"Label","b":"1F3F7","j":["sale","tag"]},"money-bag":{"a":"Money Bag","b":"1F4B0","j":["bag","dollar","money","moneybag","payment","coins","sale"]},"coin":{"a":"Coin","b":"1FA99","j":["gold","metal","money","silver","treasure","currency"]},"yen-banknote":{"a":"Yen Banknote","b":"1F4B4","j":["banknote","bill","currency","money","note","yen","sales","japanese","dollar"]},"dollar-banknote":{"a":"Dollar Banknote","b":"1F4B5","j":["banknote","bill","currency","dollar","money","note","sales"]},"euro-banknote":{"a":"Euro Banknote","b":"1F4B6","j":["banknote","bill","currency","euro","money","note","sales","dollar"]},"pound-banknote":{"a":"Pound Banknote","b":"1F4B7","j":["banknote","bill","currency","money","note","pound","british","sterling","sales","bills","uk","england"]},"money-with-wings":{"a":"Money with Wings","b":"1F4B8","j":["banknote","bill","fly","money","wings","dollar","bills","payment","sale"]},"credit-card":{"a":"Credit Card","b":"1F4B3","j":["card","credit","money","sales","dollar","bill","payment","shopping"]},"receipt":{"a":"Receipt","b":"1F9FE","j":["accounting","bookkeeping","evidence","proof","expenses"]},"chart-increasing-with-yen":{"a":"Chart Increasing with Yen","b":"1F4B9","j":["chart","graph","growth","money","yen","green-square","presentation","stats"]},"envelope":{"a":"Envelope","b":"2709","j":["email","letter","postal","inbox","communication"]},"email":{"a":"E-Mail","b":"1F4E7","j":["e-mail","letter","mail","e_mail","communication","inbox"]},"incoming-envelope":{"a":"Incoming Envelope","b":"1F4E8","j":["e-mail","email","envelope","incoming","letter","receive","inbox"]},"envelope-with-arrow":{"a":"Envelope with Arrow","b":"1F4E9","j":["arrow","e-mail","email","envelope","outgoing","communication"]},"outbox-tray":{"a":"Outbox Tray","b":"1F4E4","j":["box","letter","mail","outbox","sent","tray","inbox","email"]},"inbox-tray":{"a":"Inbox Tray","b":"1F4E5","j":["box","inbox","letter","mail","receive","tray","email","documents"]},"package":{"a":"Package","b":"1F4E6","j":["box","parcel","mail","gift","cardboard","moving"]},"closed-mailbox-with-raised-flag":{"a":"Closed Mailbox with Raised Flag","b":"1F4EB","j":["closed","mail","mailbox","postbox","email","inbox","communication"]},"closed-mailbox-with-lowered-flag":{"a":"Closed Mailbox with Lowered Flag","b":"1F4EA","j":["closed","lowered","mail","mailbox","postbox","email","communication","inbox"]},"open-mailbox-with-raised-flag":{"a":"Open Mailbox with Raised Flag","b":"1F4EC","j":["mail","mailbox","open","postbox","email","inbox","communication"]},"open-mailbox-with-lowered-flag":{"a":"Open Mailbox with Lowered Flag","b":"1F4ED","j":["lowered","mail","mailbox","open","postbox","email","inbox"]},"postbox":{"a":"Postbox","b":"1F4EE","j":["mail","mailbox","email","letter","envelope"]},"ballot-box-with-ballot":{"a":"Ballot Box with Ballot","b":"1F5F3","j":["ballot","box","election","vote"]},"pencil":{"a":"Pencil","b":"270F","j":["stationery","write","paper","writing","school","study"]},"black-nib":{"a":"Black Nib","b":"2712","j":["nib","pen","stationery","writing","write"]},"fountain-pen":{"a":"Fountain Pen","b":"1F58B","j":["fountain","pen","stationery","writing","write"]},"pen":{"a":"Pen","b":"1F58A","j":["ballpoint","stationery","writing","write"]},"paintbrush":{"a":"Paintbrush","b":"1F58C","j":["painting","drawing","creativity","art"]},"crayon":{"a":"Crayon","b":"1F58D","j":["drawing","creativity"]},"memo":{"a":"Memo","b":"1F4DD","j":["pencil","write","documents","stationery","paper","writing","legal","exam","quiz","test","study","compose"]},"briefcase":{"a":"Briefcase","b":"1F4BC","j":["business","documents","work","law","legal","job","career"]},"file-folder":{"a":"File Folder","b":"1F4C1","j":["file","folder","documents","business","office"]},"open-file-folder":{"a":"Open File Folder","b":"1F4C2","j":["file","folder","open","documents","load"]},"card-index-dividers":{"a":"Card Index Dividers","b":"1F5C2","j":["card","dividers","index","organizing","business","stationery"]},"calendar":{"a":"Calendar","b":"1F4C5","j":["date","schedule"]},"tearoff-calendar":{"a":"Tear-off Calendar","b":"1F4C6","j":["calendar","tear-off calendar","tear_off_calendar","schedule","date","planning"]},"spiral-notepad":{"a":"Spiral Notepad","b":"1F5D2","j":["note","pad","spiral","memo","stationery"]},"spiral-calendar":{"a":"Spiral Calendar","b":"1F5D3","j":["calendar","pad","spiral","date","schedule","planning"]},"card-index":{"a":"Card Index","b":"1F4C7","j":["card","index","rolodex","business","stationery"]},"chart-increasing":{"a":"Chart Increasing","b":"1F4C8","j":["chart","graph","growth","trend","upward","presentation","stats","recovery","business","economics","money","sales","good","success"]},"chart-decreasing":{"a":"Chart Decreasing","b":"1F4C9","j":["chart","down","graph","trend","presentation","stats","recession","business","economics","money","sales","bad","failure"]},"bar-chart":{"a":"Bar Chart","b":"1F4CA","j":["bar","chart","graph","presentation","stats"]},"clipboard":{"a":"Clipboard","b":"1F4CB","j":["stationery","documents"]},"pushpin":{"a":"Pushpin","b":"1F4CC","j":["pin","stationery","mark","here"]},"round-pushpin":{"a":"Round Pushpin","b":"1F4CD","j":["pin","pushpin","stationery","location","map","here"]},"paperclip":{"a":"Paperclip","b":"1F4CE","j":["documents","stationery"]},"linked-paperclips":{"a":"Linked Paperclips","b":"1F587","j":["link","paperclip","documents","stationery"]},"straight-ruler":{"a":"Straight Ruler","b":"1F4CF","j":["ruler","straight edge","stationery","calculate","length","math","school","drawing","architect","sketch"]},"triangular-ruler":{"a":"Triangular Ruler","b":"1F4D0","j":["ruler","set","triangle","stationery","math","architect","sketch"]},"scissors":{"a":"Scissors","b":"2702","j":["cutting","tool","stationery","cut"]},"card-file-box":{"a":"Card File Box","b":"1F5C3","j":["box","card","file","business","stationery"]},"file-cabinet":{"a":"File Cabinet","b":"1F5C4","j":["cabinet","file","filing","organizing"]},"wastebasket":{"a":"Wastebasket","b":"1F5D1","j":["bin","trash","rubbish","garbage","toss"]},"locked":{"a":"Locked","b":"1F512","j":["closed","security","password","padlock"]},"unlocked":{"a":"Unlocked","b":"1F513","j":["lock","open","unlock","privacy","security"]},"locked-with-pen":{"a":"Locked with Pen","b":"1F50F","j":["ink","lock","nib","pen","privacy","security","secret"]},"locked-with-key":{"a":"Locked with Key","b":"1F510","j":["closed","key","lock","secure","security","privacy"]},"key":{"a":"Key","b":"1F511","j":["lock","password","door"]},"old-key":{"a":"Old Key","b":"1F5DD","j":["clue","key","lock","old","door","password"]},"hammer":{"a":"Hammer","b":"1F528","j":["tool","tools","build","create"]},"axe":{"a":"Axe","b":"1FA93","j":["chop","hatchet","split","wood","tool","cut"]},"pick":{"a":"Pick","b":"26CF","j":["mining","tool","tools","dig"]},"hammer-and-pick":{"a":"Hammer and Pick","b":"2692","j":["hammer","pick","tool","tools","build","create"]},"hammer-and-wrench":{"a":"Hammer and Wrench","b":"1F6E0","j":["hammer","spanner","tool","wrench","tools","build","create"]},"dagger":{"a":"Dagger","b":"1F5E1","j":["knife","weapon"]},"crossed-swords":{"a":"Crossed Swords","b":"2694","j":["crossed","swords","weapon"]},"water-pistol":{"a":"Water Pistol","b":"1F52B","j":["gun","handgun","pistol","revolver","tool","water","weapon","violence"]},"boomerang":{"a":"Boomerang","b":"1FA83","j":["australia","rebound","repercussion","weapon"]},"bow-and-arrow":{"a":"Bow and Arrow","b":"1F3F9","j":["archer","arrow","bow","Sagittarius","zodiac","sports"]},"shield":{"a":"Shield","b":"1F6E1","j":["weapon","protection","security"]},"carpentry-saw":{"a":"Carpentry Saw","b":"1FA9A","j":["carpenter","lumber","saw","tool","cut","chop"]},"wrench":{"a":"Wrench","b":"1F527","j":["spanner","tool","tools","diy","ikea","fix","maintainer"]},"screwdriver":{"a":"Screwdriver","b":"1FA9B","j":["screw","tool","tools"]},"nut-and-bolt":{"a":"Nut and Bolt","b":"1F529","j":["bolt","nut","tool","handy","tools","fix"]},"gear":{"a":"Gear","b":"2699","j":["cog","cogwheel","tool"]},"clamp":{"a":"Clamp","b":"1F5DC","j":["compress","tool","vice"]},"balance-scale":{"a":"Balance Scale","b":"2696","j":["balance","justice","Libra","scale","zodiac","law","fairness","weight"]},"white-cane":{"a":"White Cane","b":"1F9AF","j":["accessibility","blind","probing_cane"]},"link":{"a":"Link","b":"1F517","j":["rings","url"]},"chains":{"a":"Chains","b":"26D3","j":["chain","lock","arrest"]},"hook":{"a":"Hook","b":"1FA9D","j":["catch","crook","curve","ensnare","selling point","tools"]},"toolbox":{"a":"Toolbox","b":"1F9F0","j":["chest","mechanic","tool","tools","diy","fix","maintainer"]},"magnet":{"a":"Magnet","b":"1F9F2","j":["attraction","horseshoe","magnetic"]},"ladder":{"a":"Ladder","b":"1FA9C","j":["climb","rung","step","tools"]},"alembic":{"a":"Alembic","b":"2697","j":["chemistry","tool","distilling","science","experiment"]},"test-tube":{"a":"Test Tube","b":"1F9EA","j":["chemist","chemistry","experiment","lab","science"]},"petri-dish":{"a":"Petri Dish","b":"1F9EB","j":["bacteria","biologist","biology","culture","lab"]},"dna":{"a":"Dna","b":"1F9EC","j":["biologist","evolution","gene","genetics","life"]},"microscope":{"a":"Microscope","b":"1F52C","j":["science","tool","laboratory","experiment","zoomin","study"]},"telescope":{"a":"Telescope","b":"1F52D","j":["science","tool","stars","space","zoom","astronomy"]},"satellite-antenna":{"a":"Satellite Antenna","b":"1F4E1","j":["antenna","dish","satellite","communication","future","radio","space"]},"syringe":{"a":"Syringe","b":"1F489","j":["medicine","needle","shot","sick","health","hospital","drugs","blood","doctor","nurse"]},"drop-of-blood":{"a":"Drop of Blood","b":"1FA78","j":["bleed","blood donation","injury","medicine","menstruation","period","hurt","harm","wound"]},"pill":{"a":"Pill","b":"1F48A","j":["doctor","medicine","sick","health","pharmacy","drug"]},"adhesive-bandage":{"a":"Adhesive Bandage","b":"1FA79","j":["bandage","heal"]},"crutch":{"a":"⊛ Crutch","b":"1FA7C","j":["cane","disability","hurt","mobility aid","stick"]},"stethoscope":{"a":"Stethoscope","b":"1FA7A","j":["doctor","heart","medicine","health"]},"xray":{"a":"⊛ X-Ray","b":"1FA7B","j":["bones","doctor","medical","skeleton"]},"door":{"a":"Door","b":"1F6AA","j":["house","entry","exit"]},"elevator":{"a":"Elevator","b":"1F6D7","j":["accessibility","hoist","lift"]},"mirror":{"a":"Mirror","b":"1FA9E","j":["reflection","reflector","speculum"]},"window":{"a":"Window","b":"1FA9F","j":["frame","fresh air","opening","transparent","view","scenery"]},"bed":{"a":"Bed","b":"1F6CF","j":["hotel","sleep","rest"]},"couch-and-lamp":{"a":"Couch and Lamp","b":"1F6CB","j":["couch","hotel","lamp","read","chill"]},"chair":{"a":"Chair","b":"1FA91","j":["seat","sit","furniture"]},"toilet":{"a":"Toilet","b":"1F6BD","j":["restroom","wc","washroom","bathroom","potty"]},"plunger":{"a":"Plunger","b":"1FAA0","j":["force cup","plumber","suction","toilet"]},"shower":{"a":"Shower","b":"1F6BF","j":["water","clean","bathroom"]},"bathtub":{"a":"Bathtub","b":"1F6C1","j":["bath","clean","shower","bathroom"]},"mouse-trap":{"a":"Mouse Trap","b":"1FAA4","j":["bait","mousetrap","snare","trap","cheese"]},"razor":{"a":"Razor","b":"1FA92","j":["sharp","shave","cut"]},"lotion-bottle":{"a":"Lotion Bottle","b":"1F9F4","j":["lotion","moisturizer","shampoo","sunscreen"]},"safety-pin":{"a":"Safety Pin","b":"1F9F7","j":["diaper","punk rock"]},"broom":{"a":"Broom","b":"1F9F9","j":["cleaning","sweeping","witch"]},"basket":{"a":"Basket","b":"1F9FA","j":["farming","laundry","picnic"]},"roll-of-paper":{"a":"Roll of Paper","b":"1F9FB","j":["paper towels","toilet paper","roll"]},"bucket":{"a":"Bucket","b":"1FAA3","j":["cask","pail","vat","water","container"]},"soap":{"a":"Soap","b":"1F9FC","j":["bar","bathing","cleaning","lather","soapdish"]},"bubbles":{"a":"⊛ Bubbles","b":"1FAE7","j":["burp","clean","soap","underwater"]},"toothbrush":{"a":"Toothbrush","b":"1FAA5","j":["bathroom","brush","clean","dental","hygiene","teeth"]},"sponge":{"a":"Sponge","b":"1F9FD","j":["absorbing","cleaning","porous"]},"fire-extinguisher":{"a":"Fire Extinguisher","b":"1F9EF","j":["extinguish","fire","quench"]},"shopping-cart":{"a":"Shopping Cart","b":"1F6D2","j":["cart","shopping","trolley"]},"cigarette":{"a":"Cigarette","b":"1F6AC","j":["smoking","kills","tobacco","joint","smoke"]},"coffin":{"a":"Coffin","b":"26B0","j":["death","vampire","dead","die","rip","graveyard","cemetery","casket","funeral","box"]},"headstone":{"a":"Headstone","b":"1FAA6","j":["cemetery","grave","graveyard","tombstone","death","rip"]},"funeral-urn":{"a":"Funeral Urn","b":"26B1","j":["ashes","death","funeral","urn","dead","die","rip"]},"moai":{"a":"Moai","b":"1F5FF","j":["face","moyai","statue","rock","easter island"]},"placard":{"a":"Placard","b":"1FAA7","j":["demonstration","picket","protest","sign","announcement"]},"identification-card":{"a":"⊛ Identification Card","b":"1FAAA","j":["credentials","ID","license","security"]},"atm-sign":{"a":"Atm Sign","b":"1F3E7","j":["atm","ATM sign","automated","bank","teller","money","sales","cash","blue-square","payment"]},"litter-in-bin-sign":{"a":"Litter in Bin Sign","b":"1F6AE","j":["litter","litter bin","blue-square","sign","human","info"]},"potable-water":{"a":"Potable Water","b":"1F6B0","j":["drinking","potable","water","blue-square","liquid","restroom","cleaning","faucet"]},"wheelchair-symbol":{"a":"Wheelchair Symbol","b":"267F","j":["access","blue-square","disabled","accessibility"]},"mens-room":{"a":"Men’S Room","b":"1F6B9","j":["lavatory","man","men’s room","restroom","wc","men_s_room","toilet","blue-square","gender","male"]},"womens-room":{"a":"Women’S Room","b":"1F6BA","j":["lavatory","restroom","wc","woman","women’s room","women_s_room","purple-square","female","toilet","loo","gender"]},"restroom":{"a":"Restroom","b":"1F6BB","j":["lavatory","WC","blue-square","toilet","refresh","wc","gender"]},"baby-symbol":{"a":"Baby Symbol","b":"1F6BC","j":["baby","changing","orange-square","child"]},"water-closet":{"a":"Water Closet","b":"1F6BE","j":["closet","lavatory","restroom","water","wc","toilet","blue-square"]},"passport-control":{"a":"Passport Control","b":"1F6C2","j":["control","passport","custom","blue-square"]},"customs":{"a":"Customs","b":"1F6C3","j":["passport","border","blue-square"]},"baggage-claim":{"a":"Baggage Claim","b":"1F6C4","j":["baggage","claim","blue-square","airport","transport"]},"left-luggage":{"a":"Left Luggage","b":"1F6C5","j":["baggage","locker","luggage","blue-square","travel"]},"warning":{"a":"Warning","b":"26A0","j":["exclamation","wip","alert","error","problem","issue"]},"children-crossing":{"a":"Children Crossing","b":"1F6B8","j":["child","crossing","pedestrian","traffic","school","warning","danger","sign","driving","yellow-diamond"]},"no-entry":{"a":"No Entry","b":"26D4","j":["entry","forbidden","no","not","prohibited","traffic","limit","security","privacy","bad","denied","stop","circle"]},"prohibited":{"a":"Prohibited","b":"1F6AB","j":["entry","forbidden","no","not","forbid","stop","limit","denied","disallow","circle"]},"no-bicycles":{"a":"No Bicycles","b":"1F6B3","j":["bicycle","bike","forbidden","no","prohibited","cyclist","circle"]},"no-smoking":{"a":"No Smoking","b":"1F6AD","j":["forbidden","no","not","prohibited","smoking","cigarette","blue-square","smell","smoke"]},"no-littering":{"a":"No Littering","b":"1F6AF","j":["forbidden","litter","no","not","prohibited","trash","bin","garbage","circle"]},"nonpotable-water":{"a":"Non-Potable Water","b":"1F6B1","j":["non-drinking","non-potable","water","non_potable_water","drink","faucet","tap","circle"]},"no-pedestrians":{"a":"No Pedestrians","b":"1F6B7","j":["forbidden","no","not","pedestrian","prohibited","rules","crossing","walking","circle"]},"no-mobile-phones":{"a":"No Mobile Phones","b":"1F4F5","j":["cell","forbidden","mobile","no","phone","iphone","mute","circle"]},"no-one-under-eighteen":{"a":"No One Under Eighteen","b":"1F51E","j":["18","age restriction","eighteen","prohibited","underage","drink","pub","night","minor","circle"]},"radioactive":{"a":"Radioactive","b":"2622","j":["sign","nuclear","danger"]},"biohazard":{"a":"Biohazard","b":"2623","j":["sign","danger"]},"up-arrow":{"a":"Up Arrow","b":"2B06","j":["arrow","cardinal","direction","north","blue-square","continue","top"]},"upright-arrow":{"a":"Up-Right Arrow","b":"2197","j":["arrow","direction","intercardinal","northeast","up-right arrow","up_right_arrow","blue-square","point","diagonal"]},"right-arrow":{"a":"Right Arrow","b":"27A1","j":["arrow","cardinal","direction","east","blue-square","next"]},"downright-arrow":{"a":"Down-Right Arrow","b":"2198","j":["arrow","direction","down-right arrow","intercardinal","southeast","down_right_arrow","blue-square","diagonal"]},"down-arrow":{"a":"Down Arrow","b":"2B07","j":["arrow","cardinal","direction","down","south","blue-square","bottom"]},"downleft-arrow":{"a":"Down-Left Arrow","b":"2199","j":["arrow","direction","down-left arrow","intercardinal","southwest","down_left_arrow","blue-square","diagonal"]},"left-arrow":{"a":"Left Arrow","b":"2B05","j":["arrow","cardinal","direction","west","blue-square","previous","back"]},"upleft-arrow":{"a":"Up-Left Arrow","b":"2196","j":["arrow","direction","intercardinal","northwest","up-left arrow","up_left_arrow","blue-square","point","diagonal"]},"updown-arrow":{"a":"Up-Down Arrow","b":"2195","j":["arrow","up-down arrow","up_down_arrow","blue-square","direction","way","vertical"]},"leftright-arrow":{"a":"Left-Right Arrow","b":"2194","j":["arrow","left-right arrow","left_right_arrow","shape","direction","horizontal","sideways"]},"right-arrow-curving-left":{"a":"Right Arrow Curving Left","b":"21A9","j":["arrow","back","return","blue-square","undo","enter"]},"left-arrow-curving-right":{"a":"Left Arrow Curving Right","b":"21AA","j":["arrow","blue-square","return","rotate","direction"]},"right-arrow-curving-up":{"a":"Right Arrow Curving Up","b":"2934","j":["arrow","blue-square","direction","top"]},"right-arrow-curving-down":{"a":"Right Arrow Curving Down","b":"2935","j":["arrow","down","blue-square","direction","bottom"]},"clockwise-vertical-arrows":{"a":"Clockwise Vertical Arrows","b":"1F503","j":["arrow","clockwise","reload","sync","cycle","round","repeat"]},"counterclockwise-arrows-button":{"a":"Counterclockwise Arrows Button","b":"1F504","j":["anticlockwise","arrow","counterclockwise","withershins","blue-square","sync","cycle"]},"back-arrow":{"a":"Back Arrow","b":"1F519","j":["arrow","back","BACK arrow","words","return"]},"end-arrow":{"a":"End Arrow","b":"1F51A","j":["arrow","end","END arrow","words"]},"on-arrow":{"a":"On! Arrow","b":"1F51B","j":["arrow","mark","on","ON! arrow","words"]},"soon-arrow":{"a":"Soon Arrow","b":"1F51C","j":["arrow","soon","SOON arrow","words"]},"top-arrow":{"a":"Top Arrow","b":"1F51D","j":["arrow","top","TOP arrow","up","words","blue-square"]},"place-of-worship":{"a":"Place of Worship","b":"1F6D0","j":["religion","worship","church","temple","prayer"]},"atom-symbol":{"a":"Atom Symbol","b":"269B","j":["atheist","atom","science","physics","chemistry"]},"om":{"a":"Om","b":"1F549","j":["Hindu","religion","hinduism","buddhism","sikhism","jainism"]},"star-of-david":{"a":"Star of David","b":"2721","j":["David","Jew","Jewish","religion","star","star of David","judaism"]},"wheel-of-dharma":{"a":"Wheel of Dharma","b":"2638","j":["Buddhist","dharma","religion","wheel","hinduism","buddhism","sikhism","jainism"]},"yin-yang":{"a":"Yin Yang","b":"262F","j":["religion","tao","taoist","yang","yin","balance"]},"latin-cross":{"a":"Latin Cross","b":"271D","j":["Christian","cross","religion","christianity"]},"orthodox-cross":{"a":"Orthodox Cross","b":"2626","j":["Christian","cross","religion","suppedaneum"]},"star-and-crescent":{"a":"Star and Crescent","b":"262A","j":["islam","Muslim","religion"]},"peace-symbol":{"a":"Peace Symbol","b":"262E","j":["peace","hippie"]},"menorah":{"a":"Menorah","b":"1F54E","j":["candelabrum","candlestick","religion","hanukkah","candles","jewish"]},"dotted-sixpointed-star":{"a":"Dotted Six-Pointed Star","b":"1F52F","j":["dotted six-pointed star","fortune","star","dotted_six_pointed_star","purple-square","religion","jewish","hexagram"]},"aries":{"a":"Aries","b":"2648","j":["ram","zodiac","sign","purple-square","astrology"]},"taurus":{"a":"Taurus","b":"2649","j":["bull","ox","zodiac","purple-square","sign","astrology"]},"gemini":{"a":"Gemini","b":"264A","j":["twins","zodiac","sign","purple-square","astrology"]},"cancer":{"a":"Cancer","b":"264B","j":["crab","zodiac","sign","purple-square","astrology"]},"leo":{"a":"Leo","b":"264C","j":["lion","zodiac","sign","purple-square","astrology"]},"virgo":{"a":"Virgo","b":"264D","j":["zodiac","sign","purple-square","astrology"]},"libra":{"a":"Libra","b":"264E","j":["balance","justice","scales","zodiac","sign","purple-square","astrology"]},"scorpio":{"a":"Scorpio","b":"264F","j":["scorpion","scorpius","zodiac","sign","purple-square","astrology"]},"sagittarius":{"a":"Sagittarius","b":"2650","j":["archer","zodiac","sign","purple-square","astrology"]},"capricorn":{"a":"Capricorn","b":"2651","j":["goat","zodiac","sign","purple-square","astrology"]},"aquarius":{"a":"Aquarius","b":"2652","j":["bearer","water","zodiac","sign","purple-square","astrology"]},"pisces":{"a":"Pisces","b":"2653","j":["fish","zodiac","purple-square","sign","astrology"]},"ophiuchus":{"a":"Ophiuchus","b":"26CE","j":["bearer","serpent","snake","zodiac","sign","purple-square","constellation","astrology"]},"shuffle-tracks-button":{"a":"Shuffle Tracks Button","b":"1F500","j":["arrow","crossed","blue-square","shuffle","music","random"]},"repeat-button":{"a":"Repeat Button","b":"1F501","j":["arrow","clockwise","repeat","loop","record"]},"repeat-single-button":{"a":"Repeat Single Button","b":"1F502","j":["arrow","clockwise","once","blue-square","loop"]},"play-button":{"a":"Play Button","b":"25B6","j":["arrow","play","right","triangle","blue-square","direction"]},"fastforward-button":{"a":"Fast-Forward Button","b":"23E9","j":["arrow","double","fast","fast-forward button","forward","fast_forward_button","blue-square","play","speed","continue"]},"next-track-button":{"a":"Next Track Button","b":"23ED","j":["arrow","next scene","next track","triangle","forward","next","blue-square"]},"play-or-pause-button":{"a":"Play or Pause Button","b":"23EF","j":["arrow","pause","play","right","triangle","blue-square"]},"reverse-button":{"a":"Reverse Button","b":"25C0","j":["arrow","left","reverse","triangle","blue-square","direction"]},"fast-reverse-button":{"a":"Fast Reverse Button","b":"23EA","j":["arrow","double","rewind","play","blue-square"]},"last-track-button":{"a":"Last Track Button","b":"23EE","j":["arrow","previous scene","previous track","triangle","backward"]},"upwards-button":{"a":"Upwards Button","b":"1F53C","j":["arrow","button","red","blue-square","triangle","direction","point","forward","top"]},"fast-up-button":{"a":"Fast Up Button","b":"23EB","j":["arrow","double","blue-square","direction","top"]},"downwards-button":{"a":"Downwards Button","b":"1F53D","j":["arrow","button","down","red","blue-square","direction","bottom"]},"fast-down-button":{"a":"Fast Down Button","b":"23EC","j":["arrow","double","down","blue-square","direction","bottom"]},"pause-button":{"a":"Pause Button","b":"23F8","j":["bar","double","pause","vertical","blue-square"]},"stop-button":{"a":"Stop Button","b":"23F9","j":["square","stop","blue-square"]},"record-button":{"a":"Record Button","b":"23FA","j":["circle","record","blue-square"]},"eject-button":{"a":"Eject Button","b":"23CF","j":["eject","blue-square"]},"cinema":{"a":"Cinema","b":"1F3A6","j":["camera","film","movie","blue-square","record","curtain","stage","theater"]},"dim-button":{"a":"Dim Button","b":"1F505","j":["brightness","dim","low","sun","afternoon","warm","summer"]},"bright-button":{"a":"Bright Button","b":"1F506","j":["bright","brightness","sun","light"]},"antenna-bars":{"a":"Antenna Bars","b":"1F4F6","j":["antenna","bar","cell","mobile","phone","blue-square","reception","internet","connection","wifi","bluetooth","bars"]},"vibration-mode":{"a":"Vibration Mode","b":"1F4F3","j":["cell","mobile","mode","phone","telephone","vibration","orange-square"]},"mobile-phone-off":{"a":"Mobile Phone off","b":"1F4F4","j":["cell","mobile","off","phone","telephone","mute","orange-square","silence","quiet"]},"female-sign":{"a":"Female Sign","b":"2640","j":["woman","women","lady","girl"]},"male-sign":{"a":"Male Sign","b":"2642","j":["man","boy","men"]},"transgender-symbol":{"a":"Transgender Symbol","b":"26A7","j":["transgender","lgbtq"]},"multiply":{"a":"Multiply","b":"2716","j":["×","cancel","multiplication","sign","x","multiplication_sign","math","calculation"]},"plus":{"a":"Plus","b":"2795","j":["+","math","sign","plus_sign","calculation","addition","more","increase"]},"minus":{"a":"Minus","b":"2796","j":["-","−","math","sign","minus_sign","calculation","subtract","less"]},"divide":{"a":"Divide","b":"2797","j":["÷","division","math","sign","division_sign","calculation"]},"heavy-equals-sign":{"a":"⊛ Heavy Equals Sign","b":"1F7F0","j":["equality","math"]},"infinity":{"a":"Infinity","b":"267E","j":["forever","unbounded","universal"]},"double-exclamation-mark":{"a":"Double Exclamation Mark","b":"203C","j":["!","!!","bangbang","exclamation","mark","surprise"]},"exclamation-question-mark":{"a":"Exclamation Question Mark","b":"2049","j":["!","!?","?","exclamation","interrobang","mark","punctuation","question","wat","surprise"]},"red-question-mark":{"a":"Red Question Mark","b":"2753","j":["?","mark","punctuation","question","question_mark","doubt","confused"]},"white-question-mark":{"a":"White Question Mark","b":"2754","j":["?","mark","outlined","punctuation","question","doubts","gray","huh","confused"]},"white-exclamation-mark":{"a":"White Exclamation Mark","b":"2755","j":["!","exclamation","mark","outlined","punctuation","surprise","gray","wow","warning"]},"red-exclamation-mark":{"a":"Red Exclamation Mark","b":"2757","j":["!","exclamation","mark","punctuation","exclamation_mark","heavy_exclamation_mark","danger","surprise","wow","warning"]},"wavy-dash":{"a":"Wavy Dash","b":"3030","j":["dash","punctuation","wavy","draw","line","moustache","mustache","squiggle","scribble"]},"currency-exchange":{"a":"Currency Exchange","b":"1F4B1","j":["bank","currency","exchange","money","sales","dollar","travel"]},"heavy-dollar-sign":{"a":"Heavy Dollar Sign","b":"1F4B2","j":["currency","dollar","money","sales","payment","buck"]},"medical-symbol":{"a":"Medical Symbol","b":"2695","j":["aesculapius","medicine","staff","health","hospital"]},"recycling-symbol":{"a":"Recycling Symbol","b":"267B","j":["recycle","arrow","environment","garbage","trash"]},"fleurdelis":{"a":"Fleur-De-Lis","b":"269C","j":["fleur-de-lis","fleur_de_lis","decorative","scout"]},"trident-emblem":{"a":"Trident Emblem","b":"1F531","j":["anchor","emblem","ship","tool","trident","weapon","spear"]},"name-badge":{"a":"Name Badge","b":"1F4DB","j":["badge","name","fire","forbid"]},"japanese-symbol-for-beginner":{"a":"Japanese Symbol for Beginner","b":"1F530","j":["beginner","chevron","Japanese","Japanese symbol for beginner","leaf","badge","shield"]},"hollow-red-circle":{"a":"Hollow Red Circle","b":"2B55","j":["circle","large","o","red","round"]},"check-mark-button":{"a":"Check Mark Button","b":"2705","j":["✓","button","check","mark","green-square","ok","agree","vote","election","answer","tick"]},"check-box-with-check":{"a":"Check Box with Check","b":"2611","j":["✓","box","check","ok","agree","confirm","black-square","vote","election","yes","tick"]},"check-mark":{"a":"Check Mark","b":"2714","j":["✓","check","mark","ok","nike","answer","yes","tick"]},"cross-mark":{"a":"Cross Mark","b":"274C","j":["×","cancel","cross","mark","multiplication","multiply","x","no","delete","remove","red"]},"cross-mark-button":{"a":"Cross Mark Button","b":"274E","j":["×","mark","square","x","green-square","no","deny"]},"curly-loop":{"a":"Curly Loop","b":"27B0","j":["curl","loop","scribble","draw","shape","squiggle"]},"double-curly-loop":{"a":"Double Curly Loop","b":"27BF","j":["curl","double","loop","tape","cassette"]},"part-alternation-mark":{"a":"Part Alternation Mark","b":"303D","j":["mark","part","graph","presentation","stats","business","economics","bad"]},"eightspoked-asterisk":{"a":"Eight-Spoked Asterisk","b":"2733","j":["*","asterisk","eight-spoked asterisk","eight_spoked_asterisk","star","sparkle","green-square"]},"eightpointed-star":{"a":"Eight-Pointed Star","b":"2734","j":["*","eight-pointed star","star","eight_pointed_star","orange-square","shape","polygon"]},"sparkle":{"a":"Sparkle","b":"2747","j":["*","stars","green-square","awesome","good","fireworks"]},"copyright":{"a":"Copyright","b":"00A9","j":["c","ip","license","circle","law","legal"]},"registered":{"a":"Registered","b":"00AE","j":["r","alphabet","circle"]},"trade-mark":{"a":"Trade Mark","b":"2122","j":["mark","tm","trademark","brand","law","legal"]},"keycap":{"a":"Keycap: *","b":"002A-FE0F-20E3","j":["keycap_","star"]},"keycap-0":{"a":"Keycap: 0","b":"0030-FE0F-20E3","j":["keycap","0","numbers","blue-square","null"]},"keycap-1":{"a":"Keycap: 1","b":"0031-FE0F-20E3","j":["keycap","blue-square","numbers","1"]},"keycap-2":{"a":"Keycap: 2","b":"0032-FE0F-20E3","j":["keycap","numbers","2","prime","blue-square"]},"keycap-3":{"a":"Keycap: 3","b":"0033-FE0F-20E3","j":["keycap","3","numbers","prime","blue-square"]},"keycap-4":{"a":"Keycap: 4","b":"0034-FE0F-20E3","j":["keycap","4","numbers","blue-square"]},"keycap-5":{"a":"Keycap: 5","b":"0035-FE0F-20E3","j":["keycap","5","numbers","blue-square","prime"]},"keycap-6":{"a":"Keycap: 6","b":"0036-FE0F-20E3","j":["keycap","6","numbers","blue-square"]},"keycap-7":{"a":"Keycap: 7","b":"0037-FE0F-20E3","j":["keycap","7","numbers","blue-square","prime"]},"keycap-8":{"a":"Keycap: 8","b":"0038-FE0F-20E3","j":["keycap","8","blue-square","numbers"]},"keycap-9":{"a":"Keycap: 9","b":"0039-FE0F-20E3","j":["keycap","blue-square","numbers","9"]},"keycap-10":{"a":"Keycap: 10","b":"1F51F","j":["keycap","numbers","10","blue-square"]},"input-latin-uppercase":{"a":"Input Latin Uppercase","b":"1F520","j":["ABCD","input","latin","letters","uppercase","alphabet","words","blue-square"]},"input-latin-lowercase":{"a":"Input Latin Lowercase","b":"1F521","j":["abcd","input","latin","letters","lowercase","blue-square","alphabet"]},"input-numbers":{"a":"Input Numbers","b":"1F522","j":["1234","input","numbers","blue-square"]},"input-symbols":{"a":"Input Symbols","b":"1F523","j":["〒♪&%","input","blue-square","music","note","ampersand","percent","glyphs","characters"]},"input-latin-letters":{"a":"Input Latin Letters","b":"1F524","j":["abc","alphabet","input","latin","letters","blue-square"]},"a-button-blood-type":{"a":"A Button (Blood Type)","b":"1F170","j":["a","A button (blood type)","blood type","a_button","red-square","alphabet","letter"]},"ab-button-blood-type":{"a":"Ab Button (Blood Type)","b":"1F18E","j":["ab","AB button (blood type)","blood type","ab_button","red-square","alphabet"]},"b-button-blood-type":{"a":"B Button (Blood Type)","b":"1F171","j":["b","B button (blood type)","blood type","b_button","red-square","alphabet","letter"]},"cl-button":{"a":"Cl Button","b":"1F191","j":["cl","CL button","alphabet","words","red-square"]},"cool-button":{"a":"Cool Button","b":"1F192","j":["cool","COOL button","words","blue-square"]},"free-button":{"a":"Free Button","b":"1F193","j":["free","FREE button","blue-square","words"]},"information":{"a":"Information","b":"2139","j":["i","blue-square","alphabet","letter"]},"id-button":{"a":"Id Button","b":"1F194","j":["id","ID button","identity","purple-square","words"]},"circled-m":{"a":"Circled M","b":"24C2","j":["circle","circled M","m","alphabet","blue-circle","letter"]},"new-button":{"a":"New Button","b":"1F195","j":["new","NEW button","blue-square","words","start"]},"ng-button":{"a":"Ng Button","b":"1F196","j":["ng","NG button","blue-square","words","shape","icon"]},"o-button-blood-type":{"a":"O Button (Blood Type)","b":"1F17E","j":["blood type","o","O button (blood type)","o_button","alphabet","red-square","letter"]},"ok-button":{"a":"Ok Button","b":"1F197","j":["OK","OK button","good","agree","yes","blue-square"]},"p-button":{"a":"P Button","b":"1F17F","j":["P button","parking","cars","blue-square","alphabet","letter"]},"sos-button":{"a":"Sos Button","b":"1F198","j":["help","sos","SOS button","red-square","words","emergency","911"]},"up-button":{"a":"Up! Button","b":"1F199","j":["mark","up","UP! button","blue-square","above","high"]},"vs-button":{"a":"Vs Button","b":"1F19A","j":["versus","vs","VS button","words","orange-square"]},"japanese-here-button":{"a":"Japanese “Here” Button","b":"1F201","j":["“here”","Japanese","Japanese “here” button","katakana","ココ","blue-square","here","japanese","destination"]},"japanese-service-charge-button":{"a":"Japanese “Service Charge” Button","b":"1F202","j":["“service charge”","Japanese","Japanese “service charge” button","katakana","サ","japanese","blue-square"]},"japanese-monthly-amount-button":{"a":"Japanese “Monthly Amount” Button","b":"1F237","j":["“monthly amount”","ideograph","Japanese","Japanese “monthly amount” button","月","chinese","month","moon","japanese","orange-square","kanji"]},"japanese-not-free-of-charge-button":{"a":"Japanese “Not Free of Charge” Button","b":"1F236","j":["“not free of charge”","ideograph","Japanese","Japanese “not free of charge” button","有","orange-square","chinese","have","kanji"]},"japanese-reserved-button":{"a":"Japanese “Reserved” Button","b":"1F22F","j":["“reserved”","ideograph","Japanese","Japanese “reserved” button","指","chinese","point","green-square","kanji"]},"japanese-bargain-button":{"a":"Japanese “Bargain” Button","b":"1F250","j":["“bargain”","ideograph","Japanese","Japanese “bargain” button","得","chinese","kanji","obtain","get","circle"]},"japanese-discount-button":{"a":"Japanese “Discount” Button","b":"1F239","j":["“discount”","ideograph","Japanese","Japanese “discount” button","割","cut","divide","chinese","kanji","pink-square"]},"japanese-free-of-charge-button":{"a":"Japanese “Free of Charge” Button","b":"1F21A","j":["“free of charge”","ideograph","Japanese","Japanese “free of charge” button","無","nothing","chinese","kanji","japanese","orange-square"]},"japanese-prohibited-button":{"a":"Japanese “Prohibited” Button","b":"1F232","j":["“prohibited”","ideograph","Japanese","Japanese “prohibited” button","禁","kanji","japanese","chinese","forbidden","limit","restricted","red-square"]},"japanese-acceptable-button":{"a":"Japanese “Acceptable” Button","b":"1F251","j":["“acceptable”","ideograph","Japanese","Japanese “acceptable” button","可","ok","good","chinese","kanji","agree","yes","orange-circle"]},"japanese-application-button":{"a":"Japanese “Application” Button","b":"1F238","j":["“application”","ideograph","Japanese","Japanese “application” button","申","chinese","japanese","kanji","orange-square"]},"japanese-passing-grade-button":{"a":"Japanese “Passing Grade” Button","b":"1F234","j":["“passing grade”","ideograph","Japanese","Japanese “passing grade” button","合","japanese","chinese","join","kanji","red-square"]},"japanese-vacancy-button":{"a":"Japanese “Vacancy” Button","b":"1F233","j":["“vacancy”","ideograph","Japanese","Japanese “vacancy” button","空","kanji","japanese","chinese","empty","sky","blue-square"]},"japanese-congratulations-button":{"a":"Japanese “Congratulations” Button","b":"3297","j":["“congratulations”","ideograph","Japanese","Japanese “congratulations” button","祝","chinese","kanji","japanese","red-circle"]},"japanese-secret-button":{"a":"Japanese “Secret” Button","b":"3299","j":["“secret”","ideograph","Japanese","Japanese “secret” button","秘","privacy","chinese","sshh","kanji","red-circle"]},"japanese-open-for-business-button":{"a":"Japanese “Open for Business” Button","b":"1F23A","j":["“open for business”","ideograph","Japanese","Japanese “open for business” button","営","japanese","opening hours","orange-square"]},"japanese-no-vacancy-button":{"a":"Japanese “No Vacancy” Button","b":"1F235","j":["“no vacancy”","ideograph","Japanese","Japanese “no vacancy” button","満","full","chinese","japanese","red-square","kanji"]},"red-circle":{"a":"Red Circle","b":"1F534","j":["circle","geometric","red","shape","error","danger"]},"orange-circle":{"a":"Orange Circle","b":"1F7E0","j":["circle","orange","round"]},"yellow-circle":{"a":"Yellow Circle","b":"1F7E1","j":["circle","yellow","round"]},"green-circle":{"a":"Green Circle","b":"1F7E2","j":["circle","green","round"]},"blue-circle":{"a":"Blue Circle","b":"1F535","j":["blue","circle","geometric","shape","icon","button"]},"purple-circle":{"a":"Purple Circle","b":"1F7E3","j":["circle","purple","round"]},"brown-circle":{"a":"Brown Circle","b":"1F7E4","j":["brown","circle","round"]},"black-circle":{"a":"Black Circle","b":"26AB","j":["circle","geometric","shape","button","round"]},"white-circle":{"a":"White Circle","b":"26AA","j":["circle","geometric","shape","round"]},"red-square":{"a":"Red Square","b":"1F7E5","j":["red","square"]},"orange-square":{"a":"Orange Square","b":"1F7E7","j":["orange","square"]},"yellow-square":{"a":"Yellow Square","b":"1F7E8","j":["square","yellow"]},"green-square":{"a":"Green Square","b":"1F7E9","j":["green","square"]},"blue-square":{"a":"Blue Square","b":"1F7E6","j":["blue","square"]},"purple-square":{"a":"Purple Square","b":"1F7EA","j":["purple","square"]},"brown-square":{"a":"Brown Square","b":"1F7EB","j":["brown","square"]},"black-large-square":{"a":"Black Large Square","b":"2B1B","j":["geometric","square","shape","icon","button"]},"white-large-square":{"a":"White Large Square","b":"2B1C","j":["geometric","square","shape","icon","stone","button"]},"black-medium-square":{"a":"Black Medium Square","b":"25FC","j":["geometric","square","shape","button","icon"]},"white-medium-square":{"a":"White Medium Square","b":"25FB","j":["geometric","square","shape","stone","icon"]},"black-mediumsmall-square":{"a":"Black Medium-Small Square","b":"25FE","j":["black medium-small square","geometric","square","black_medium_small_square","icon","shape","button"]},"white-mediumsmall-square":{"a":"White Medium-Small Square","b":"25FD","j":["geometric","square","white medium-small square","white_medium_small_square","shape","stone","icon","button"]},"black-small-square":{"a":"Black Small Square","b":"25AA","j":["geometric","square","shape","icon"]},"white-small-square":{"a":"White Small Square","b":"25AB","j":["geometric","square","shape","icon"]},"large-orange-diamond":{"a":"Large Orange Diamond","b":"1F536","j":["diamond","geometric","orange","shape","jewel","gem"]},"large-blue-diamond":{"a":"Large Blue Diamond","b":"1F537","j":["blue","diamond","geometric","shape","jewel","gem"]},"small-orange-diamond":{"a":"Small Orange Diamond","b":"1F538","j":["diamond","geometric","orange","shape","jewel","gem"]},"small-blue-diamond":{"a":"Small Blue Diamond","b":"1F539","j":["blue","diamond","geometric","shape","jewel","gem"]},"red-triangle-pointed-up":{"a":"Red Triangle Pointed Up","b":"1F53A","j":["geometric","red","shape","direction","up","top"]},"red-triangle-pointed-down":{"a":"Red Triangle Pointed Down","b":"1F53B","j":["down","geometric","red","shape","direction","bottom"]},"diamond-with-a-dot":{"a":"Diamond with a Dot","b":"1F4A0","j":["comic","diamond","geometric","inside","jewel","blue","gem","crystal","fancy"]},"radio-button":{"a":"Radio Button","b":"1F518","j":["button","geometric","radio","input","old","music","circle"]},"white-square-button":{"a":"White Square Button","b":"1F533","j":["button","geometric","outlined","square","shape","input"]},"black-square-button":{"a":"Black Square Button","b":"1F532","j":["button","geometric","square","shape","input","frame"]},"chequered-flag":{"a":"Chequered Flag","b":"1F3C1","j":["checkered","chequered","racing","contest","finishline","race","gokart"]},"triangular-flag":{"a":"Triangular Flag","b":"1F6A9","j":["post","mark","milestone","place"]},"crossed-flags":{"a":"Crossed Flags","b":"1F38C","j":["celebration","cross","crossed","Japanese","japanese","nation","country","border"]},"black-flag":{"a":"Black Flag","b":"1F3F4","j":["waving","pirate"]},"white-flag":{"a":"White Flag","b":"1F3F3","j":["waving","losing","loser","lost","surrender","give up","fail"]},"rainbow-flag":{"a":"Rainbow Flag","b":"1F3F3-FE0F-200D-1F308","j":["pride","rainbow","flag","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"]},"transgender-flag":{"a":"Transgender Flag","b":"1F3F3-FE0F-200D-26A7-FE0F","j":["flag","light blue","pink","transgender","white","lgbtq"]},"pirate-flag":{"a":"Pirate Flag","b":"1F3F4-200D-2620-FE0F","j":["Jolly Roger","pirate","plunder","treasure","skull","crossbones","flag","banner"]},"flag-ascension-island":{"a":"Flag: Ascension Island","b":"1F1E6-1F1E8","j":["flag"]},"flag-andorra":{"a":"Flag: Andorra","b":"1F1E6-1F1E9","j":["flag","ad","nation","country","banner","andorra"]},"flag-united-arab-emirates":{"a":"Flag: United Arab Emirates","b":"1F1E6-1F1EA","j":["flag","united","arab","emirates","nation","country","banner","united_arab_emirates"]},"flag-afghanistan":{"a":"Flag: Afghanistan","b":"1F1E6-1F1EB","j":["flag","af","nation","country","banner","afghanistan"]},"flag-antigua--barbuda":{"a":"Flag: Antigua & Barbuda","b":"1F1E6-1F1EC","j":["flag","flag_antigua_barbuda","antigua","barbuda","nation","country","banner","antigua_barbuda"]},"flag-anguilla":{"a":"Flag: Anguilla","b":"1F1E6-1F1EE","j":["flag","ai","nation","country","banner","anguilla"]},"flag-albania":{"a":"Flag: Albania","b":"1F1E6-1F1F1","j":["flag","al","nation","country","banner","albania"]},"flag-armenia":{"a":"Flag: Armenia","b":"1F1E6-1F1F2","j":["flag","am","nation","country","banner","armenia"]},"flag-angola":{"a":"Flag: Angola","b":"1F1E6-1F1F4","j":["flag","ao","nation","country","banner","angola"]},"flag-antarctica":{"a":"Flag: Antarctica","b":"1F1E6-1F1F6","j":["flag","aq","nation","country","banner","antarctica"]},"flag-argentina":{"a":"Flag: Argentina","b":"1F1E6-1F1F7","j":["flag","ar","nation","country","banner","argentina"]},"flag-american-samoa":{"a":"Flag: American Samoa","b":"1F1E6-1F1F8","j":["flag","american","ws","nation","country","banner","american_samoa"]},"flag-austria":{"a":"Flag: Austria","b":"1F1E6-1F1F9","j":["flag","at","nation","country","banner","austria"]},"flag-australia":{"a":"Flag: Australia","b":"1F1E6-1F1FA","j":["flag","au","nation","country","banner","australia"]},"flag-aruba":{"a":"Flag: Aruba","b":"1F1E6-1F1FC","j":["flag","aw","nation","country","banner","aruba"]},"flag-land-islands":{"a":"Flag: Åland Islands","b":"1F1E6-1F1FD","j":["flag","flag_aland_islands","Åland","islands","nation","country","banner","aland_islands"]},"flag-azerbaijan":{"a":"Flag: Azerbaijan","b":"1F1E6-1F1FF","j":["flag","az","nation","country","banner","azerbaijan"]},"flag-bosnia--herzegovina":{"a":"Flag: Bosnia & Herzegovina","b":"1F1E7-1F1E6","j":["flag","flag_bosnia_herzegovina","bosnia","herzegovina","nation","country","banner","bosnia_herzegovina"]},"flag-barbados":{"a":"Flag: Barbados","b":"1F1E7-1F1E7","j":["flag","bb","nation","country","banner","barbados"]},"flag-bangladesh":{"a":"Flag: Bangladesh","b":"1F1E7-1F1E9","j":["flag","bd","nation","country","banner","bangladesh"]},"flag-belgium":{"a":"Flag: Belgium","b":"1F1E7-1F1EA","j":["flag","be","nation","country","banner","belgium"]},"flag-burkina-faso":{"a":"Flag: Burkina Faso","b":"1F1E7-1F1EB","j":["flag","burkina","faso","nation","country","banner","burkina_faso"]},"flag-bulgaria":{"a":"Flag: Bulgaria","b":"1F1E7-1F1EC","j":["flag","bg","nation","country","banner","bulgaria"]},"flag-bahrain":{"a":"Flag: Bahrain","b":"1F1E7-1F1ED","j":["flag","bh","nation","country","banner","bahrain"]},"flag-burundi":{"a":"Flag: Burundi","b":"1F1E7-1F1EE","j":["flag","bi","nation","country","banner","burundi"]},"flag-benin":{"a":"Flag: Benin","b":"1F1E7-1F1EF","j":["flag","bj","nation","country","banner","benin"]},"flag-st-barthlemy":{"a":"Flag: St. Barthélemy","b":"1F1E7-1F1F1","j":["flag","flag_st_barthelemy","saint","barthélemy","nation","country","banner","st_barthelemy"]},"flag-bermuda":{"a":"Flag: Bermuda","b":"1F1E7-1F1F2","j":["flag","bm","nation","country","banner","bermuda"]},"flag-brunei":{"a":"Flag: Brunei","b":"1F1E7-1F1F3","j":["flag","bn","darussalam","nation","country","banner","brunei"]},"flag-bolivia":{"a":"Flag: Bolivia","b":"1F1E7-1F1F4","j":["flag","bo","nation","country","banner","bolivia"]},"flag-caribbean-netherlands":{"a":"Flag: Caribbean Netherlands","b":"1F1E7-1F1F6","j":["flag","bonaire","nation","country","banner","caribbean_netherlands"]},"flag-brazil":{"a":"Flag: Brazil","b":"1F1E7-1F1F7","j":["flag","br","nation","country","banner","brazil"]},"flag-bahamas":{"a":"Flag: Bahamas","b":"1F1E7-1F1F8","j":["flag","bs","nation","country","banner","bahamas"]},"flag-bhutan":{"a":"Flag: Bhutan","b":"1F1E7-1F1F9","j":["flag","bt","nation","country","banner","bhutan"]},"flag-bouvet-island":{"a":"Flag: Bouvet Island","b":"1F1E7-1F1FB","j":["flag","norway"]},"flag-botswana":{"a":"Flag: Botswana","b":"1F1E7-1F1FC","j":["flag","bw","nation","country","banner","botswana"]},"flag-belarus":{"a":"Flag: Belarus","b":"1F1E7-1F1FE","j":["flag","by","nation","country","banner","belarus"]},"flag-belize":{"a":"Flag: Belize","b":"1F1E7-1F1FF","j":["flag","bz","nation","country","banner","belize"]},"flag-canada":{"a":"Flag: Canada","b":"1F1E8-1F1E6","j":["flag","ca","nation","country","banner","canada"]},"flag-cocos-keeling-islands":{"a":"Flag: Cocos (Keeling) Islands","b":"1F1E8-1F1E8","j":["flag","flag_cocos_islands","cocos","keeling","islands","nation","country","banner","cocos_islands"]},"flag-congo--kinshasa":{"a":"Flag: Congo - Kinshasa","b":"1F1E8-1F1E9","j":["flag","flag_congo_kinshasa","congo","democratic","republic","nation","country","banner","congo_kinshasa"]},"flag-central-african-republic":{"a":"Flag: Central African Republic","b":"1F1E8-1F1EB","j":["flag","central","african","republic","nation","country","banner","central_african_republic"]},"flag-congo--brazzaville":{"a":"Flag: Congo - Brazzaville","b":"1F1E8-1F1EC","j":["flag","flag_congo_brazzaville","congo","nation","country","banner","congo_brazzaville"]},"flag-switzerland":{"a":"Flag: Switzerland","b":"1F1E8-1F1ED","j":["flag","ch","nation","country","banner","switzerland"]},"flag-cte-divoire":{"a":"Flag: Côte D’Ivoire","b":"1F1E8-1F1EE","j":["flag","flag_cote_d_ivoire","ivory","coast","nation","country","banner","cote_d_ivoire"]},"flag-cook-islands":{"a":"Flag: Cook Islands","b":"1F1E8-1F1F0","j":["flag","cook","islands","nation","country","banner","cook_islands"]},"flag-chile":{"a":"Flag: Chile","b":"1F1E8-1F1F1","j":["flag","nation","country","banner","chile"]},"flag-cameroon":{"a":"Flag: Cameroon","b":"1F1E8-1F1F2","j":["flag","cm","nation","country","banner","cameroon"]},"flag-china":{"a":"Flag: China","b":"1F1E8-1F1F3","j":["flag","china","chinese","prc","country","nation","banner"]},"flag-colombia":{"a":"Flag: Colombia","b":"1F1E8-1F1F4","j":["flag","co","nation","country","banner","colombia"]},"flag-clipperton-island":{"a":"Flag: Clipperton Island","b":"1F1E8-1F1F5","j":["flag"]},"flag-costa-rica":{"a":"Flag: Costa Rica","b":"1F1E8-1F1F7","j":["flag","costa","rica","nation","country","banner","costa_rica"]},"flag-cuba":{"a":"Flag: Cuba","b":"1F1E8-1F1FA","j":["flag","cu","nation","country","banner","cuba"]},"flag-cape-verde":{"a":"Flag: Cape Verde","b":"1F1E8-1F1FB","j":["flag","cabo","verde","nation","country","banner","cape_verde"]},"flag-curaao":{"a":"Flag: Curaçao","b":"1F1E8-1F1FC","j":["flag","flag_curacao","curaçao","nation","country","banner","curacao"]},"flag-christmas-island":{"a":"Flag: Christmas Island","b":"1F1E8-1F1FD","j":["flag","christmas","island","nation","country","banner","christmas_island"]},"flag-cyprus":{"a":"Flag: Cyprus","b":"1F1E8-1F1FE","j":["flag","cy","nation","country","banner","cyprus"]},"flag-czechia":{"a":"Flag: Czechia","b":"1F1E8-1F1FF","j":["flag","cz","nation","country","banner","czechia"]},"flag-germany":{"a":"Flag: Germany","b":"1F1E9-1F1EA","j":["flag","german","nation","country","banner","germany"]},"flag-diego-garcia":{"a":"Flag: Diego Garcia","b":"1F1E9-1F1EC","j":["flag"]},"flag-djibouti":{"a":"Flag: Djibouti","b":"1F1E9-1F1EF","j":["flag","dj","nation","country","banner","djibouti"]},"flag-denmark":{"a":"Flag: Denmark","b":"1F1E9-1F1F0","j":["flag","dk","nation","country","banner","denmark"]},"flag-dominica":{"a":"Flag: Dominica","b":"1F1E9-1F1F2","j":["flag","dm","nation","country","banner","dominica"]},"flag-dominican-republic":{"a":"Flag: Dominican Republic","b":"1F1E9-1F1F4","j":["flag","dominican","republic","nation","country","banner","dominican_republic"]},"flag-algeria":{"a":"Flag: Algeria","b":"1F1E9-1F1FF","j":["flag","dz","nation","country","banner","algeria"]},"flag-ceuta--melilla":{"a":"Flag: Ceuta & Melilla","b":"1F1EA-1F1E6","j":["flag","flag_ceuta_melilla"]},"flag-ecuador":{"a":"Flag: Ecuador","b":"1F1EA-1F1E8","j":["flag","ec","nation","country","banner","ecuador"]},"flag-estonia":{"a":"Flag: Estonia","b":"1F1EA-1F1EA","j":["flag","ee","nation","country","banner","estonia"]},"flag-egypt":{"a":"Flag: Egypt","b":"1F1EA-1F1EC","j":["flag","eg","nation","country","banner","egypt"]},"flag-western-sahara":{"a":"Flag: Western Sahara","b":"1F1EA-1F1ED","j":["flag","western","sahara","nation","country","banner","western_sahara"]},"flag-eritrea":{"a":"Flag: Eritrea","b":"1F1EA-1F1F7","j":["flag","er","nation","country","banner","eritrea"]},"flag-spain":{"a":"Flag: Spain","b":"1F1EA-1F1F8","j":["flag","spain","nation","country","banner"]},"flag-ethiopia":{"a":"Flag: Ethiopia","b":"1F1EA-1F1F9","j":["flag","et","nation","country","banner","ethiopia"]},"flag-european-union":{"a":"Flag: European Union","b":"1F1EA-1F1FA","j":["flag","european","union","banner"]},"flag-finland":{"a":"Flag: Finland","b":"1F1EB-1F1EE","j":["flag","fi","nation","country","banner","finland"]},"flag-fiji":{"a":"Flag: Fiji","b":"1F1EB-1F1EF","j":["flag","fj","nation","country","banner","fiji"]},"flag-falkland-islands":{"a":"Flag: Falkland Islands","b":"1F1EB-1F1F0","j":["flag","falkland","islands","malvinas","nation","country","banner","falkland_islands"]},"flag-micronesia":{"a":"Flag: Micronesia","b":"1F1EB-1F1F2","j":["flag","micronesia","federated","states","nation","country","banner"]},"flag-faroe-islands":{"a":"Flag: Faroe Islands","b":"1F1EB-1F1F4","j":["flag","faroe","islands","nation","country","banner","faroe_islands"]},"flag-france":{"a":"Flag: France","b":"1F1EB-1F1F7","j":["flag","banner","nation","france","french","country"]},"flag-gabon":{"a":"Flag: Gabon","b":"1F1EC-1F1E6","j":["flag","ga","nation","country","banner","gabon"]},"flag-united-kingdom":{"a":"Flag: United Kingdom","b":"1F1EC-1F1E7","j":["flag","united","kingdom","great","britain","northern","ireland","nation","country","banner","british","UK","english","england","union jack","united_kingdom"]},"flag-grenada":{"a":"Flag: Grenada","b":"1F1EC-1F1E9","j":["flag","gd","nation","country","banner","grenada"]},"flag-georgia":{"a":"Flag: Georgia","b":"1F1EC-1F1EA","j":["flag","ge","nation","country","banner","georgia"]},"flag-french-guiana":{"a":"Flag: French Guiana","b":"1F1EC-1F1EB","j":["flag","french","guiana","nation","country","banner","french_guiana"]},"flag-guernsey":{"a":"Flag: Guernsey","b":"1F1EC-1F1EC","j":["flag","gg","nation","country","banner","guernsey"]},"flag-ghana":{"a":"Flag: Ghana","b":"1F1EC-1F1ED","j":["flag","gh","nation","country","banner","ghana"]},"flag-gibraltar":{"a":"Flag: Gibraltar","b":"1F1EC-1F1EE","j":["flag","gi","nation","country","banner","gibraltar"]},"flag-greenland":{"a":"Flag: Greenland","b":"1F1EC-1F1F1","j":["flag","gl","nation","country","banner","greenland"]},"flag-gambia":{"a":"Flag: Gambia","b":"1F1EC-1F1F2","j":["flag","gm","nation","country","banner","gambia"]},"flag-guinea":{"a":"Flag: Guinea","b":"1F1EC-1F1F3","j":["flag","gn","nation","country","banner","guinea"]},"flag-guadeloupe":{"a":"Flag: Guadeloupe","b":"1F1EC-1F1F5","j":["flag","gp","nation","country","banner","guadeloupe"]},"flag-equatorial-guinea":{"a":"Flag: Equatorial Guinea","b":"1F1EC-1F1F6","j":["flag","equatorial","gn","nation","country","banner","equatorial_guinea"]},"flag-greece":{"a":"Flag: Greece","b":"1F1EC-1F1F7","j":["flag","gr","nation","country","banner","greece"]},"flag-south-georgia--south-sandwich-islands":{"a":"Flag: South Georgia & South Sandwich Islands","b":"1F1EC-1F1F8","j":["flag","flag_south_georgia_south_sandwich_islands","south","georgia","sandwich","islands","nation","country","banner","south_georgia_south_sandwich_islands"]},"flag-guatemala":{"a":"Flag: Guatemala","b":"1F1EC-1F1F9","j":["flag","gt","nation","country","banner","guatemala"]},"flag-guam":{"a":"Flag: Guam","b":"1F1EC-1F1FA","j":["flag","gu","nation","country","banner","guam"]},"flag-guineabissau":{"a":"Flag: Guinea-Bissau","b":"1F1EC-1F1FC","j":["flag","flag_guinea_bissau","gw","bissau","nation","country","banner","guinea_bissau"]},"flag-guyana":{"a":"Flag: Guyana","b":"1F1EC-1F1FE","j":["flag","gy","nation","country","banner","guyana"]},"flag-hong-kong-sar-china":{"a":"Flag: Hong Kong Sar China","b":"1F1ED-1F1F0","j":["flag","hong","kong","nation","country","banner","hong_kong_sar_china"]},"flag-heard--mcdonald-islands":{"a":"Flag: Heard & Mcdonald Islands","b":"1F1ED-1F1F2","j":["flag","flag_heard_mcdonald_islands"]},"flag-honduras":{"a":"Flag: Honduras","b":"1F1ED-1F1F3","j":["flag","hn","nation","country","banner","honduras"]},"flag-croatia":{"a":"Flag: Croatia","b":"1F1ED-1F1F7","j":["flag","hr","nation","country","banner","croatia"]},"flag-haiti":{"a":"Flag: Haiti","b":"1F1ED-1F1F9","j":["flag","ht","nation","country","banner","haiti"]},"flag-hungary":{"a":"Flag: Hungary","b":"1F1ED-1F1FA","j":["flag","hu","nation","country","banner","hungary"]},"flag-canary-islands":{"a":"Flag: Canary Islands","b":"1F1EE-1F1E8","j":["flag","canary","islands","nation","country","banner","canary_islands"]},"flag-indonesia":{"a":"Flag: Indonesia","b":"1F1EE-1F1E9","j":["flag","nation","country","banner","indonesia"]},"flag-ireland":{"a":"Flag: Ireland","b":"1F1EE-1F1EA","j":["flag","ie","nation","country","banner","ireland"]},"flag-israel":{"a":"Flag: Israel","b":"1F1EE-1F1F1","j":["flag","il","nation","country","banner","israel"]},"flag-isle-of-man":{"a":"Flag: Isle of Man","b":"1F1EE-1F1F2","j":["flag","isle","man","nation","country","banner","isle_of_man"]},"flag-india":{"a":"Flag: India","b":"1F1EE-1F1F3","j":["flag","in","nation","country","banner","india"]},"flag-british-indian-ocean-territory":{"a":"Flag: British Indian Ocean Territory","b":"1F1EE-1F1F4","j":["flag","british","indian","ocean","territory","nation","country","banner","british_indian_ocean_territory"]},"flag-iraq":{"a":"Flag: Iraq","b":"1F1EE-1F1F6","j":["flag","iq","nation","country","banner","iraq"]},"flag-iran":{"a":"Flag: Iran","b":"1F1EE-1F1F7","j":["flag","iran","islamic","republic","nation","country","banner"]},"flag-iceland":{"a":"Flag: Iceland","b":"1F1EE-1F1F8","j":["flag","is","nation","country","banner","iceland"]},"flag-italy":{"a":"Flag: Italy","b":"1F1EE-1F1F9","j":["flag","italy","nation","country","banner"]},"flag-jersey":{"a":"Flag: Jersey","b":"1F1EF-1F1EA","j":["flag","je","nation","country","banner","jersey"]},"flag-jamaica":{"a":"Flag: Jamaica","b":"1F1EF-1F1F2","j":["flag","jm","nation","country","banner","jamaica"]},"flag-jordan":{"a":"Flag: Jordan","b":"1F1EF-1F1F4","j":["flag","jo","nation","country","banner","jordan"]},"flag-japan":{"a":"Flag: Japan","b":"1F1EF-1F1F5","j":["flag","japanese","nation","country","banner","japan"]},"flag-kenya":{"a":"Flag: Kenya","b":"1F1F0-1F1EA","j":["flag","ke","nation","country","banner","kenya"]},"flag-kyrgyzstan":{"a":"Flag: Kyrgyzstan","b":"1F1F0-1F1EC","j":["flag","kg","nation","country","banner","kyrgyzstan"]},"flag-cambodia":{"a":"Flag: Cambodia","b":"1F1F0-1F1ED","j":["flag","kh","nation","country","banner","cambodia"]},"flag-kiribati":{"a":"Flag: Kiribati","b":"1F1F0-1F1EE","j":["flag","ki","nation","country","banner","kiribati"]},"flag-comoros":{"a":"Flag: Comoros","b":"1F1F0-1F1F2","j":["flag","km","nation","country","banner","comoros"]},"flag-st-kitts--nevis":{"a":"Flag: St. Kitts & Nevis","b":"1F1F0-1F1F3","j":["flag","flag_st_kitts_nevis","saint","kitts","nevis","nation","country","banner","st_kitts_nevis"]},"flag-north-korea":{"a":"Flag: North Korea","b":"1F1F0-1F1F5","j":["flag","north","korea","nation","country","banner","north_korea"]},"flag-south-korea":{"a":"Flag: South Korea","b":"1F1F0-1F1F7","j":["flag","south","korea","nation","country","banner","south_korea"]},"flag-kuwait":{"a":"Flag: Kuwait","b":"1F1F0-1F1FC","j":["flag","kw","nation","country","banner","kuwait"]},"flag-cayman-islands":{"a":"Flag: Cayman Islands","b":"1F1F0-1F1FE","j":["flag","cayman","islands","nation","country","banner","cayman_islands"]},"flag-kazakhstan":{"a":"Flag: Kazakhstan","b":"1F1F0-1F1FF","j":["flag","kz","nation","country","banner","kazakhstan"]},"flag-laos":{"a":"Flag: Laos","b":"1F1F1-1F1E6","j":["flag","lao","democratic","republic","nation","country","banner","laos"]},"flag-lebanon":{"a":"Flag: Lebanon","b":"1F1F1-1F1E7","j":["flag","lb","nation","country","banner","lebanon"]},"flag-st-lucia":{"a":"Flag: St. Lucia","b":"1F1F1-1F1E8","j":["flag","saint","lucia","nation","country","banner","st_lucia"]},"flag-liechtenstein":{"a":"Flag: Liechtenstein","b":"1F1F1-1F1EE","j":["flag","li","nation","country","banner","liechtenstein"]},"flag-sri-lanka":{"a":"Flag: Sri Lanka","b":"1F1F1-1F1F0","j":["flag","sri","lanka","nation","country","banner","sri_lanka"]},"flag-liberia":{"a":"Flag: Liberia","b":"1F1F1-1F1F7","j":["flag","lr","nation","country","banner","liberia"]},"flag-lesotho":{"a":"Flag: Lesotho","b":"1F1F1-1F1F8","j":["flag","ls","nation","country","banner","lesotho"]},"flag-lithuania":{"a":"Flag: Lithuania","b":"1F1F1-1F1F9","j":["flag","lt","nation","country","banner","lithuania"]},"flag-luxembourg":{"a":"Flag: Luxembourg","b":"1F1F1-1F1FA","j":["flag","lu","nation","country","banner","luxembourg"]},"flag-latvia":{"a":"Flag: Latvia","b":"1F1F1-1F1FB","j":["flag","lv","nation","country","banner","latvia"]},"flag-libya":{"a":"Flag: Libya","b":"1F1F1-1F1FE","j":["flag","ly","nation","country","banner","libya"]},"flag-morocco":{"a":"Flag: Morocco","b":"1F1F2-1F1E6","j":["flag","ma","nation","country","banner","morocco"]},"flag-monaco":{"a":"Flag: Monaco","b":"1F1F2-1F1E8","j":["flag","mc","nation","country","banner","monaco"]},"flag-moldova":{"a":"Flag: Moldova","b":"1F1F2-1F1E9","j":["flag","moldova","republic","nation","country","banner"]},"flag-montenegro":{"a":"Flag: Montenegro","b":"1F1F2-1F1EA","j":["flag","me","nation","country","banner","montenegro"]},"flag-st-martin":{"a":"Flag: St. Martin","b":"1F1F2-1F1EB","j":["flag"]},"flag-madagascar":{"a":"Flag: Madagascar","b":"1F1F2-1F1EC","j":["flag","mg","nation","country","banner","madagascar"]},"flag-marshall-islands":{"a":"Flag: Marshall Islands","b":"1F1F2-1F1ED","j":["flag","marshall","islands","nation","country","banner","marshall_islands"]},"flag-north-macedonia":{"a":"Flag: North Macedonia","b":"1F1F2-1F1F0","j":["flag","macedonia","nation","country","banner","north_macedonia"]},"flag-mali":{"a":"Flag: Mali","b":"1F1F2-1F1F1","j":["flag","ml","nation","country","banner","mali"]},"flag-myanmar-burma":{"a":"Flag: Myanmar (Burma)","b":"1F1F2-1F1F2","j":["flag","flag_myanmar","mm","nation","country","banner","myanmar"]},"flag-mongolia":{"a":"Flag: Mongolia","b":"1F1F2-1F1F3","j":["flag","mn","nation","country","banner","mongolia"]},"flag-macao-sar-china":{"a":"Flag: Macao Sar China","b":"1F1F2-1F1F4","j":["flag","macao","nation","country","banner","macao_sar_china"]},"flag-northern-mariana-islands":{"a":"Flag: Northern Mariana Islands","b":"1F1F2-1F1F5","j":["flag","northern","mariana","islands","nation","country","banner","northern_mariana_islands"]},"flag-martinique":{"a":"Flag: Martinique","b":"1F1F2-1F1F6","j":["flag","mq","nation","country","banner","martinique"]},"flag-mauritania":{"a":"Flag: Mauritania","b":"1F1F2-1F1F7","j":["flag","mr","nation","country","banner","mauritania"]},"flag-montserrat":{"a":"Flag: Montserrat","b":"1F1F2-1F1F8","j":["flag","ms","nation","country","banner","montserrat"]},"flag-malta":{"a":"Flag: Malta","b":"1F1F2-1F1F9","j":["flag","mt","nation","country","banner","malta"]},"flag-mauritius":{"a":"Flag: Mauritius","b":"1F1F2-1F1FA","j":["flag","mu","nation","country","banner","mauritius"]},"flag-maldives":{"a":"Flag: Maldives","b":"1F1F2-1F1FB","j":["flag","mv","nation","country","banner","maldives"]},"flag-malawi":{"a":"Flag: Malawi","b":"1F1F2-1F1FC","j":["flag","mw","nation","country","banner","malawi"]},"flag-mexico":{"a":"Flag: Mexico","b":"1F1F2-1F1FD","j":["flag","mx","nation","country","banner","mexico"]},"flag-malaysia":{"a":"Flag: Malaysia","b":"1F1F2-1F1FE","j":["flag","my","nation","country","banner","malaysia"]},"flag-mozambique":{"a":"Flag: Mozambique","b":"1F1F2-1F1FF","j":["flag","mz","nation","country","banner","mozambique"]},"flag-namibia":{"a":"Flag: Namibia","b":"1F1F3-1F1E6","j":["flag","na","nation","country","banner","namibia"]},"flag-new-caledonia":{"a":"Flag: New Caledonia","b":"1F1F3-1F1E8","j":["flag","new","caledonia","nation","country","banner","new_caledonia"]},"flag-niger":{"a":"Flag: Niger","b":"1F1F3-1F1EA","j":["flag","ne","nation","country","banner","niger"]},"flag-norfolk-island":{"a":"Flag: Norfolk Island","b":"1F1F3-1F1EB","j":["flag","norfolk","island","nation","country","banner","norfolk_island"]},"flag-nigeria":{"a":"Flag: Nigeria","b":"1F1F3-1F1EC","j":["flag","nation","country","banner","nigeria"]},"flag-nicaragua":{"a":"Flag: Nicaragua","b":"1F1F3-1F1EE","j":["flag","ni","nation","country","banner","nicaragua"]},"flag-netherlands":{"a":"Flag: Netherlands","b":"1F1F3-1F1F1","j":["flag","nl","nation","country","banner","netherlands"]},"flag-norway":{"a":"Flag: Norway","b":"1F1F3-1F1F4","j":["flag","no","nation","country","banner","norway"]},"flag-nepal":{"a":"Flag: Nepal","b":"1F1F3-1F1F5","j":["flag","np","nation","country","banner","nepal"]},"flag-nauru":{"a":"Flag: Nauru","b":"1F1F3-1F1F7","j":["flag","nr","nation","country","banner","nauru"]},"flag-niue":{"a":"Flag: Niue","b":"1F1F3-1F1FA","j":["flag","nu","nation","country","banner","niue"]},"flag-new-zealand":{"a":"Flag: New Zealand","b":"1F1F3-1F1FF","j":["flag","new","zealand","nation","country","banner","new_zealand"]},"flag-oman":{"a":"Flag: Oman","b":"1F1F4-1F1F2","j":["flag","om_symbol","nation","country","banner","oman"]},"flag-panama":{"a":"Flag: Panama","b":"1F1F5-1F1E6","j":["flag","pa","nation","country","banner","panama"]},"flag-peru":{"a":"Flag: Peru","b":"1F1F5-1F1EA","j":["flag","pe","nation","country","banner","peru"]},"flag-french-polynesia":{"a":"Flag: French Polynesia","b":"1F1F5-1F1EB","j":["flag","french","polynesia","nation","country","banner","french_polynesia"]},"flag-papua-new-guinea":{"a":"Flag: Papua New Guinea","b":"1F1F5-1F1EC","j":["flag","papua","new","guinea","nation","country","banner","papua_new_guinea"]},"flag-philippines":{"a":"Flag: Philippines","b":"1F1F5-1F1ED","j":["flag","ph","nation","country","banner","philippines"]},"flag-pakistan":{"a":"Flag: Pakistan","b":"1F1F5-1F1F0","j":["flag","pk","nation","country","banner","pakistan"]},"flag-poland":{"a":"Flag: Poland","b":"1F1F5-1F1F1","j":["flag","pl","nation","country","banner","poland"]},"flag-st-pierre--miquelon":{"a":"Flag: St. Pierre & Miquelon","b":"1F1F5-1F1F2","j":["flag","flag_st_pierre_miquelon","saint","pierre","miquelon","nation","country","banner","st_pierre_miquelon"]},"flag-pitcairn-islands":{"a":"Flag: Pitcairn Islands","b":"1F1F5-1F1F3","j":["flag","pitcairn","nation","country","banner","pitcairn_islands"]},"flag-puerto-rico":{"a":"Flag: Puerto Rico","b":"1F1F5-1F1F7","j":["flag","puerto","rico","nation","country","banner","puerto_rico"]},"flag-palestinian-territories":{"a":"Flag: Palestinian Territories","b":"1F1F5-1F1F8","j":["flag","palestine","palestinian","territories","nation","country","banner","palestinian_territories"]},"flag-portugal":{"a":"Flag: Portugal","b":"1F1F5-1F1F9","j":["flag","pt","nation","country","banner","portugal"]},"flag-palau":{"a":"Flag: Palau","b":"1F1F5-1F1FC","j":["flag","pw","nation","country","banner","palau"]},"flag-paraguay":{"a":"Flag: Paraguay","b":"1F1F5-1F1FE","j":["flag","py","nation","country","banner","paraguay"]},"flag-qatar":{"a":"Flag: Qatar","b":"1F1F6-1F1E6","j":["flag","qa","nation","country","banner","qatar"]},"flag-runion":{"a":"Flag: Réunion","b":"1F1F7-1F1EA","j":["flag","flag_reunion","réunion","nation","country","banner","reunion"]},"flag-romania":{"a":"Flag: Romania","b":"1F1F7-1F1F4","j":["flag","ro","nation","country","banner","romania"]},"flag-serbia":{"a":"Flag: Serbia","b":"1F1F7-1F1F8","j":["flag","rs","nation","country","banner","serbia"]},"flag-russia":{"a":"Flag: Russia","b":"1F1F7-1F1FA","j":["flag","russian","federation","nation","country","banner","russia"]},"flag-rwanda":{"a":"Flag: Rwanda","b":"1F1F7-1F1FC","j":["flag","rw","nation","country","banner","rwanda"]},"flag-saudi-arabia":{"a":"Flag: Saudi Arabia","b":"1F1F8-1F1E6","j":["flag","nation","country","banner","saudi_arabia"]},"flag-solomon-islands":{"a":"Flag: Solomon Islands","b":"1F1F8-1F1E7","j":["flag","solomon","islands","nation","country","banner","solomon_islands"]},"flag-seychelles":{"a":"Flag: Seychelles","b":"1F1F8-1F1E8","j":["flag","sc","nation","country","banner","seychelles"]},"flag-sudan":{"a":"Flag: Sudan","b":"1F1F8-1F1E9","j":["flag","sd","nation","country","banner","sudan"]},"flag-sweden":{"a":"Flag: Sweden","b":"1F1F8-1F1EA","j":["flag","se","nation","country","banner","sweden"]},"flag-singapore":{"a":"Flag: Singapore","b":"1F1F8-1F1EC","j":["flag","sg","nation","country","banner","singapore"]},"flag-st-helena":{"a":"Flag: St. Helena","b":"1F1F8-1F1ED","j":["flag","saint","helena","ascension","tristan","cunha","nation","country","banner","st_helena"]},"flag-slovenia":{"a":"Flag: Slovenia","b":"1F1F8-1F1EE","j":["flag","si","nation","country","banner","slovenia"]},"flag-svalbard--jan-mayen":{"a":"Flag: Svalbard & Jan Mayen","b":"1F1F8-1F1EF","j":["flag","flag_svalbard_jan_mayen"]},"flag-slovakia":{"a":"Flag: Slovakia","b":"1F1F8-1F1F0","j":["flag","sk","nation","country","banner","slovakia"]},"flag-sierra-leone":{"a":"Flag: Sierra Leone","b":"1F1F8-1F1F1","j":["flag","sierra","leone","nation","country","banner","sierra_leone"]},"flag-san-marino":{"a":"Flag: San Marino","b":"1F1F8-1F1F2","j":["flag","san","marino","nation","country","banner","san_marino"]},"flag-senegal":{"a":"Flag: Senegal","b":"1F1F8-1F1F3","j":["flag","sn","nation","country","banner","senegal"]},"flag-somalia":{"a":"Flag: Somalia","b":"1F1F8-1F1F4","j":["flag","so","nation","country","banner","somalia"]},"flag-suriname":{"a":"Flag: Suriname","b":"1F1F8-1F1F7","j":["flag","sr","nation","country","banner","suriname"]},"flag-south-sudan":{"a":"Flag: South Sudan","b":"1F1F8-1F1F8","j":["flag","south","sd","nation","country","banner","south_sudan"]},"flag-so-tom--prncipe":{"a":"Flag: São Tomé & Príncipe","b":"1F1F8-1F1F9","j":["flag","flag_sao_tome_principe","sao","tome","principe","nation","country","banner","sao_tome_principe"]},"flag-el-salvador":{"a":"Flag: El Salvador","b":"1F1F8-1F1FB","j":["flag","el","salvador","nation","country","banner","el_salvador"]},"flag-sint-maarten":{"a":"Flag: Sint Maarten","b":"1F1F8-1F1FD","j":["flag","sint","maarten","dutch","nation","country","banner","sint_maarten"]},"flag-syria":{"a":"Flag: Syria","b":"1F1F8-1F1FE","j":["flag","syrian","arab","republic","nation","country","banner","syria"]},"flag-eswatini":{"a":"Flag: Eswatini","b":"1F1F8-1F1FF","j":["flag","sz","nation","country","banner","eswatini"]},"flag-tristan-da-cunha":{"a":"Flag: Tristan Da Cunha","b":"1F1F9-1F1E6","j":["flag"]},"flag-turks--caicos-islands":{"a":"Flag: Turks & Caicos Islands","b":"1F1F9-1F1E8","j":["flag","flag_turks_caicos_islands","turks","caicos","islands","nation","country","banner","turks_caicos_islands"]},"flag-chad":{"a":"Flag: Chad","b":"1F1F9-1F1E9","j":["flag","td","nation","country","banner","chad"]},"flag-french-southern-territories":{"a":"Flag: French Southern Territories","b":"1F1F9-1F1EB","j":["flag","french","southern","territories","nation","country","banner","french_southern_territories"]},"flag-togo":{"a":"Flag: Togo","b":"1F1F9-1F1EC","j":["flag","tg","nation","country","banner","togo"]},"flag-thailand":{"a":"Flag: Thailand","b":"1F1F9-1F1ED","j":["flag","th","nation","country","banner","thailand"]},"flag-tajikistan":{"a":"Flag: Tajikistan","b":"1F1F9-1F1EF","j":["flag","tj","nation","country","banner","tajikistan"]},"flag-tokelau":{"a":"Flag: Tokelau","b":"1F1F9-1F1F0","j":["flag","tk","nation","country","banner","tokelau"]},"flag-timorleste":{"a":"Flag: Timor-Leste","b":"1F1F9-1F1F1","j":["flag","flag_timor_leste","timor","leste","nation","country","banner","timor_leste"]},"flag-turkmenistan":{"a":"Flag: Turkmenistan","b":"1F1F9-1F1F2","j":["flag","nation","country","banner","turkmenistan"]},"flag-tunisia":{"a":"Flag: Tunisia","b":"1F1F9-1F1F3","j":["flag","tn","nation","country","banner","tunisia"]},"flag-tonga":{"a":"Flag: Tonga","b":"1F1F9-1F1F4","j":["flag","to","nation","country","banner","tonga"]},"flag-turkey":{"a":"Flag: Turkey","b":"1F1F9-1F1F7","j":["flag","turkey","nation","country","banner"]},"flag-trinidad--tobago":{"a":"Flag: Trinidad & Tobago","b":"1F1F9-1F1F9","j":["flag","flag_trinidad_tobago","trinidad","tobago","nation","country","banner","trinidad_tobago"]},"flag-tuvalu":{"a":"Flag: Tuvalu","b":"1F1F9-1F1FB","j":["flag","nation","country","banner","tuvalu"]},"flag-taiwan":{"a":"Flag: Taiwan","b":"1F1F9-1F1FC","j":["flag","tw","nation","country","banner","taiwan"]},"flag-tanzania":{"a":"Flag: Tanzania","b":"1F1F9-1F1FF","j":["flag","tanzania","united","republic","nation","country","banner"]},"flag-ukraine":{"a":"Flag: Ukraine","b":"1F1FA-1F1E6","j":["flag","ua","nation","country","banner","ukraine"]},"flag-uganda":{"a":"Flag: Uganda","b":"1F1FA-1F1EC","j":["flag","ug","nation","country","banner","uganda"]},"flag-us-outlying-islands":{"a":"Flag: U.S. Outlying Islands","b":"1F1FA-1F1F2","j":["flag","flag_u_s_outlying_islands"]},"flag-united-nations":{"a":"Flag: United Nations","b":"1F1FA-1F1F3","j":["flag","un","banner"]},"flag-united-states":{"a":"Flag: United States","b":"1F1FA-1F1F8","j":["flag","united","states","america","nation","country","banner","united_states"]},"flag-uruguay":{"a":"Flag: Uruguay","b":"1F1FA-1F1FE","j":["flag","uy","nation","country","banner","uruguay"]},"flag-uzbekistan":{"a":"Flag: Uzbekistan","b":"1F1FA-1F1FF","j":["flag","uz","nation","country","banner","uzbekistan"]},"flag-vatican-city":{"a":"Flag: Vatican City","b":"1F1FB-1F1E6","j":["flag","vatican","city","nation","country","banner","vatican_city"]},"flag-st-vincent--grenadines":{"a":"Flag: St. Vincent & Grenadines","b":"1F1FB-1F1E8","j":["flag","flag_st_vincent_grenadines","saint","vincent","grenadines","nation","country","banner","st_vincent_grenadines"]},"flag-venezuela":{"a":"Flag: Venezuela","b":"1F1FB-1F1EA","j":["flag","ve","bolivarian","republic","nation","country","banner","venezuela"]},"flag-british-virgin-islands":{"a":"Flag: British Virgin Islands","b":"1F1FB-1F1EC","j":["flag","british","virgin","islands","bvi","nation","country","banner","british_virgin_islands"]},"flag-us-virgin-islands":{"a":"Flag: U.S. Virgin Islands","b":"1F1FB-1F1EE","j":["flag","flag_u_s_virgin_islands","virgin","islands","us","nation","country","banner","u_s_virgin_islands"]},"flag-vietnam":{"a":"Flag: Vietnam","b":"1F1FB-1F1F3","j":["flag","viet","nam","nation","country","banner","vietnam"]},"flag-vanuatu":{"a":"Flag: Vanuatu","b":"1F1FB-1F1FA","j":["flag","vu","nation","country","banner","vanuatu"]},"flag-wallis--futuna":{"a":"Flag: Wallis & Futuna","b":"1F1FC-1F1EB","j":["flag","flag_wallis_futuna","wallis","futuna","nation","country","banner","wallis_futuna"]},"flag-samoa":{"a":"Flag: Samoa","b":"1F1FC-1F1F8","j":["flag","ws","nation","country","banner","samoa"]},"flag-kosovo":{"a":"Flag: Kosovo","b":"1F1FD-1F1F0","j":["flag","xk","nation","country","banner","kosovo"]},"flag-yemen":{"a":"Flag: Yemen","b":"1F1FE-1F1EA","j":["flag","ye","nation","country","banner","yemen"]},"flag-mayotte":{"a":"Flag: Mayotte","b":"1F1FE-1F1F9","j":["flag","yt","nation","country","banner","mayotte"]},"flag-south-africa":{"a":"Flag: South Africa","b":"1F1FF-1F1E6","j":["flag","south","africa","nation","country","banner","south_africa"]},"flag-zambia":{"a":"Flag: Zambia","b":"1F1FF-1F1F2","j":["flag","zm","nation","country","banner","zambia"]},"flag-zimbabwe":{"a":"Flag: Zimbabwe","b":"1F1FF-1F1FC","j":["flag","zw","nation","country","banner","zimbabwe"]},"flag-england":{"a":"Flag: England","b":"1F3F4-E0067-E0062-E0065-E006E-E0067-E007F","j":["flag","english"]},"flag-scotland":{"a":"Flag: Scotland","b":"1F3F4-E0067-E0062-E0073-E0063-E0074-E007F","j":["flag","scottish"]},"flag-wales":{"a":"Flag: Wales","b":"1F3F4-E0067-E0062-E0077-E006C-E0073-E007F","j":["flag","welsh"]}},"aliases":{}}
\ No newline at end of file
diff --git a/vector/src/main/res/values-ang/strings.xml b/vector/src/main/res/values-ang/strings.xml
new file mode 100644
index 0000000000..a6b3daec93
--- /dev/null
+++ b/vector/src/main/res/values-ang/strings.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources></resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-ar/strings.xml b/vector/src/main/res/values-ar/strings.xml
index 7833cd72a3..9ff0f695ed 100644
--- a/vector/src/main/res/values-ar/strings.xml
+++ b/vector/src/main/res/values-ar/strings.xml
@@ -8,27 +8,27 @@
     <string name="notice_room_leave">غادرَ ⁨%1$s⁩ الغرفة</string>
     <string name="notice_room_reject">رفضَ ⁨%1$s⁩ الدعوة</string>
     <string name="notice_room_kick">طردَ ⁨%1$s⁩ ⁨%2$s⁩</string>
-    <string name="notice_room_unban">رفعَ ⁨%1$s⁩ المنع عن ⁨%2$s⁩</string>
-    <string name="notice_room_ban">منعَ ⁨%1$s⁩ ⁨%2$s⁩</string>
+    <string name="notice_room_unban">رفعَ ⁨%1$s⁩ الحظر عن ⁨%2$s⁩</string>
+    <string name="notice_room_ban">حظرَ ⁨%1$s⁩ ⁨%2$s⁩</string>
     <string name="notice_avatar_url_changed">غيّر ⁨%1$s⁩ صورته الشخصية</string>
-    <string name="notice_display_name_changed_from">غيّر %1$s اسمه الظاهر من %2$s إلى %3$s</string>
-    <string name="notice_display_name_removed">أزال %1$s اسمه الظاهر (كان %2$s)</string>
+    <string name="notice_display_name_changed_from">غيّر %1$s اسمه العلنيّ من %2$s إلى %3$s</string>
+    <string name="notice_display_name_removed">أزال %1$s اسمه العلنيّ(كان %2$s)</string>
     <string name="notice_room_topic_changed">غيّر %1$s الموضوع إلى: %2$s</string>
-    <string name="notice_room_name_changed">إنَّ %1$s قد غيَّرَ اسم الغُرفة إلى: %2$s</string>
-    <string name="notice_answered_call">إنَّ %s قد أجابَ على المُكالمة.</string>
-    <string name="notice_ended_call">إنَّ %s قد أنهى المُكالمة.</string>
-    <string name="notice_made_future_room_visibility">إنَّ %1$s قد جعلَ التأريخ المُستقبلي للغُرفة مرئيًا لـ %2$s</string>
+    <string name="notice_room_name_changed">غيّر %1$s اسم الغُرفة إلى: %2$s</string>
+    <string name="notice_answered_call">أجابَ %s على المُكالمة.</string>
+    <string name="notice_ended_call">أنهى %s المُكالمة.</string>
+    <string name="notice_made_future_room_visibility">جعلَ %1$s التأريخ المُستقبلي للغُرفة مرئيًا لـ %2$s</string>
     <string name="notice_room_visibility_invited">جميع أعضاء الغُرفة، مِنَ اللَّحظة التي تمَّت دعوتهم.</string>
-    <string name="notice_room_visibility_joined">جميع أعضاء الغُرفة، مِن لحظة انضمامهم.</string>
+    <string name="notice_room_visibility_joined">جميع أعضاء الغُرفة، مِن لحظة إنضمامهم.</string>
     <string name="notice_room_visibility_shared">جميع أعضاء الغُرفة.</string>
     <string name="notice_room_visibility_world_readable">أيُّ شخص.</string>
-    <string name="notice_room_visibility_unknown">غير معروف (%s).</string>
-    <string name="notice_end_to_end">إنَّ %1$s قد فعَّلَ تعمية النهاية-إلى-النهاية (%2$s)</string>
-    <string name="notice_requested_voip_conference">إنَّ %1$s قد طلبَ اجتماع VoIP</string>
-    <string name="notice_voip_started">إنَّ اجتماع VoIP قد بدأ</string>
-    <string name="notice_voip_finished">إنَّ اجتماع VoIP قد انتهى</string>
-    <string name="notice_room_name_removed">إنَّ %1$s قد أزالَ اسم الغُرفة</string>
-    <string name="notice_room_topic_removed">إنَّ %1$s قد أزالَ موضوع الغُرفة</string>
+    <string name="notice_room_visibility_unknown">مجهول (%s).</string>
+    <string name="notice_end_to_end">فعَّلَ %1$s تشفير طرف لطرف (%2$s)</string>
+    <string name="notice_requested_voip_conference">طلبَ %1$s اجتماع VoIP</string>
+    <string name="notice_voip_started">بدأ اجتماع VoIP</string>
+    <string name="notice_voip_finished">انتهى اجتماع VoIP</string>
+    <string name="notice_room_name_removed">أزالَ %1$s اسم الغُرفة</string>
+    <string name="notice_room_topic_removed">أزالَ %1$s موضوع الغُرفة</string>
     <string name="notice_profile_change_redacted">إنَّ %1$s قد حدَّثَ ملفه الشخصي %2$s</string>
     <string name="notice_room_third_party_invite">إنَّ %1$s قد أرسلَ دعوة إلى %2$s للإنضمام إلى الغُرفة</string>
     <string name="notice_crypto_unable_to_decrypt">** يتعذَّر فك تعمية: ⁨%s⁩ **</string>
@@ -42,12 +42,12 @@
     <string name="medium_phone_number">رقم الهاتف</string>
     <string name="summary_message">‏‏⁨%1$s⁩: ‏⁨%2$s⁩</string>
     <string name="notice_room_withdraw">سحبَ ⁨%1$s⁩ الدعوة الموجّهة إلى ⁨%2$s</string>
-    <string name="notice_placed_video_call">إنَّ %s قد أجرى مُكالمة مرئية.</string>
-    <string name="notice_placed_voice_call">إنَّ %s قد أجرى مُكالمة صوتية.</string>
+    <string name="notice_placed_video_call">أجرى %s مُكالمة مرئية.</string>
+    <string name="notice_placed_voice_call">أجرى %s مُكالمة صوتية.</string>
     <string name="notice_room_third_party_registered_invite">إنَّ %1$s قد قَبَل دعوة %2$s</string>
     <string name="could_not_redact">يتعذَّر التنقيح</string>
     <string name="summary_user_sent_sticker">أرسلَ ⁨%1$s⁩ ملصقًا.</string>
-    <string name="notice_avatar_changed_too">(تمَّ تغيِّير الصُّورة أيضًا)</string>
+    <string name="notice_avatar_changed_too">(غُيرت الصُّورة أيضًا)</string>
     <string name="room_displayname_invite_from">دَعوة مِن ⁨%s⁩</string>
     <string name="room_displayname_empty_room">غُرفة فارِغة</string>
     <string name="room_displayname_two_members">%1$s وَ %2$s</string>
@@ -70,30 +70,30 @@
     <string name="notice_room_leave_by_you">غادرتَ الغرفة</string>
     <string name="notice_room_reject_by_you">رفضتَ الدعوة</string>
     <string name="notice_room_kick_by_you">طردتَ ⁨%1$s⁩</string>
-    <string name="notice_room_unban_by_you">رفعتَ المنع عن ⁨%1$s⁩</string>
-    <string name="notice_room_ban_by_you">منعتَ ⁨%1$s⁩</string>
+    <string name="notice_room_unban_by_you">رفعتَ الحظر عن ⁨%1$s⁩</string>
+    <string name="notice_room_ban_by_you">حظرتَ ⁨%1$s⁩</string>
     <string name="notice_room_withdraw_by_you">سحبتَ الدعوة الموجّهة إلى ⁨%1$s⁩</string>
     <string name="notice_avatar_url_changed_by_you">غيّرتَ صورتك الشخصية</string>
-    <string name="notice_display_name_set_by_you">عيَّنتَ اسمك الظاهر إلى %1$s</string>
-    <string name="notice_display_name_changed_from_by_you">غيّرتَ اسمك الظاهر من ⁨%1$s⁩ إلى ⁨%2$s⁩</string>
-    <string name="notice_display_name_removed_by_you">أزلتَ اسمك الظاهر (كان ⁨%1$s⁩)</string>
+    <string name="notice_display_name_set_by_you">عيَّنتَ اسمك العلنيّ إلى %1$s</string>
+    <string name="notice_display_name_changed_from_by_you">غيّرتَ اسمك العلنيّ من ⁨%1$s⁩ إلى ⁨%2$s⁩</string>
+    <string name="notice_display_name_removed_by_you">أزلتَ اسمك العلنيّ (كان ⁨%1$s⁩)</string>
     <string name="notice_room_topic_changed_by_you">غيَّرتَ الموضوع إلى: ⁨%1$s⁩</string>
-    <string name="notice_room_avatar_changed">إنَّ %1$s قد غيَّرَ صورة الغُرفة</string>
-    <string name="notice_room_avatar_changed_by_you">أنتَ قد غيَّرتَ صورة الغُرفة</string>
-    <string name="notice_room_name_changed_by_you">أنتَ قد غيَّرتَ اسم الغُرفة إلى: %1$s</string>
-    <string name="notice_placed_video_call_by_you">أنتَ قد أجريتَ مُكالمة مرئية.</string>
-    <string name="notice_placed_voice_call_by_you">أنتَ قد أجريتَ مُكالمة صوتية.</string>
-    <string name="notice_call_candidates">إنَّ %s قد أرسلَ بيانات لإعداد مُكالمة.</string>
-    <string name="notice_call_candidates_by_you">أنتَ قد أرسلتَ بيانات لإعداد مُكالمة.</string>
-    <string name="notice_answered_call_by_you">أنتَ قد أجبتَ على المُكالمة.</string>
-    <string name="notice_ended_call_by_you">أنتَ قد أنهيتَ المُكالمة.</string>
-    <string name="notice_made_future_room_visibility_by_you">أنتَ قد جعلتَ التأريخ المُستقبلي للغُرفة مرئيًا لـ %1$s</string>
-    <string name="notice_end_to_end_by_you">أنتَ قد فعَّلتَ تعيمية النهاية-إلى-النهاية (%1$s)</string>
-    <string name="notice_room_update">إنَّ %s قد قامَ بترقية هذه الغرفة.</string>
-    <string name="notice_room_update_by_you">أنتَ قد رقَّيتَ هذه الغرفة.</string>
-    <string name="notice_requested_voip_conference_by_you">أنتَ قد طلبتَ اجتماع VoIP</string>
-    <string name="notice_room_name_removed_by_you">أنتَ قد أزلتَ اسم الغُرفة</string>
-    <string name="notice_room_topic_removed_by_you">أنتَ قد أزلتَ موضوع الغُرفة</string>
+    <string name="notice_room_avatar_changed">غيَّرَ %1$s صورة الغُرفة</string>
+    <string name="notice_room_avatar_changed_by_you">غيَّرتَ صورة الغُرفة</string>
+    <string name="notice_room_name_changed_by_you">غيَّرتَ اسم الغُرفة إلى: %1$s</string>
+    <string name="notice_placed_video_call_by_you">جريتَ مُكالمة مرئية.</string>
+    <string name="notice_placed_voice_call_by_you">أجريتَ مُكالمة صوتية.</string>
+    <string name="notice_call_candidates">أرسلَ %s بيانات لإعداد مُكالمة.</string>
+    <string name="notice_call_candidates_by_you">أرسلتَ بيانات لإعداد مُكالمة.</string>
+    <string name="notice_answered_call_by_you">أجبتَ على المُكالمة.</string>
+    <string name="notice_ended_call_by_you">أنهيتَ المُكالمة.</string>
+    <string name="notice_made_future_room_visibility_by_you">جعلتَ التأريخ المُستقبلي للغُرفة مرئيًا لـ %1$s</string>
+    <string name="notice_end_to_end_by_you">فعَّلتَ تشفير طرف لطرف (%1$s)</string>
+    <string name="notice_room_update">رقّى %s هذه الغرفة.</string>
+    <string name="notice_room_update_by_you">رقَّيتَ هذه الغرفة.</string>
+    <string name="notice_requested_voip_conference_by_you">طلبتَ اجتماع VoIP</string>
+    <string name="notice_room_name_removed_by_you">أزلتَ اسم الغُرفة</string>
+    <string name="notice_room_topic_removed_by_you">أزلتَ موضوع الغُرفة</string>
     <string name="notice_room_avatar_removed">إنَّ %1$s قد أزالَ صورة الغُرفة</string>
     <string name="notice_room_avatar_removed_by_you">أنتَ قد أزلتَ صورة الغُرفة</string>
     <string name="notice_event_redacted">تمَّت إزالة الرسالة</string>
@@ -118,7 +118,7 @@
     <string name="notice_power_level_changed">إنَّ %1$s قد غيَّرَ مُستوى قوة %2$s.</string>
     <string name="notice_power_level_diff">%1$s مِن %2$s إلى %3$s</string>
     <string name="initial_sync_start_importing_account">المُزامنة الأولية:
-\nيجري إستيرد الحِساب…</string>
+\nيستورد الحِساب…</string>
     <string name="notice_room_server_acl_allow_is_empty">🎉 جميع الخوادِم محظورة مِنَ المُشاركة! لم يعُد من المُمكِن استخدام هذه الغُرفة.</string>
     <string name="notice_room_server_acl_updated_no_change">لا تغيير.</string>
     <string name="notice_room_server_acl_updated_ip_literals_not_allowed">• خوادِم مُطابقة IP الحرفية محظورة الآن.</string>
@@ -127,18 +127,18 @@
     <string name="notice_room_server_acl_updated_was_banned">• الخوادِم المُطابقة لـ %s أُزيلت مِن قائمة الحظر.</string>
     <string name="notice_room_server_acl_updated_banned">• الخوادِم المُطابقة لـ %s محظورة الآن.</string>
     <string name="notice_room_server_acl_updated_ip_literals_allowed">• خوادِم مُطابقة IP الحرفية مسموحة الآن.</string>
-    <string name="notice_room_server_acl_updated_title_by_you">أنتَ قد غيَّرتَ خادِم الـACLs لهذه الغُرفة.</string>
-    <string name="notice_room_server_acl_updated_title">إنَّ %s قد غيَّرَ خادِم الـACLs لهذه الغُرفة.</string>
-    <string name="notice_room_server_acl_set_ip_literals_not_allowed">• الخوادِم تحظُر مُطابقة القيم الحرفية للـIP.</string>
+    <string name="notice_room_server_acl_updated_title_by_you">يَّرتَ خادِم الـACLs لهذه الغُرفة.</string>
+    <string name="notice_room_server_acl_updated_title">غيَّرَ %s خادِم الـACLs لهذه الغُرفة.</string>
+    <string name="notice_room_server_acl_set_ip_literals_not_allowed">• الخوادِم المطابقة للقيم الحرفية للـIP محظورة.</string>
     <string name="notice_room_server_acl_set_allowed">• الخوادِم المُطابقة لـ %s مسموحة.</string>
     <string name="notice_room_server_acl_set_banned">• الخوادِم المُطابقة لـ %s محظورة.</string>
-    <string name="notice_room_server_acl_set_ip_literals_allowed">• الخوادِم تسمح بمُطابقة القيم الحرفية للـIP.</string>
-    <string name="notice_room_server_acl_set_title_by_you">أنتَ قد عيَّنتَ خادِم الـACLs لهذه الغُرفة.</string>
-    <string name="notice_room_server_acl_set_title">إنَّ %s قد عيَّنَ خادِم الـACLs لهذه الغُرفة.</string>
-    <string name="notice_direct_room_update_by_you">أنتَ قد قمتَ بالترقية هُنا.</string>
-    <string name="notice_direct_room_update">إنَّ %s قد قامَ بالترقية هُنا.</string>
-    <string name="notice_made_future_direct_room_visibility_by_you">أنتَ قد جعلتَ الرسائل المُستقبلية مرئية لـ %1$s</string>
-    <string name="notice_made_future_direct_room_visibility">إنَّ %1$s قد جعلَ الرسائل المُستقبلية مرئية لـ %2$s</string>
+    <string name="notice_room_server_acl_set_ip_literals_allowed">• الخوادِم المطابقة للقيم الحرفية للـIP مسموحة.</string>
+    <string name="notice_room_server_acl_set_title_by_you">عيَّنتَ خادِم الـACLs لهذه الغُرفة.</string>
+    <string name="notice_room_server_acl_set_title">عيَّنَ %s خادِم الـACLs لهذه الغُرفة.</string>
+    <string name="notice_direct_room_update_by_you">رقيتَ هُنا.</string>
+    <string name="notice_direct_room_update">رقّى %s هُنا.</string>
+    <string name="notice_made_future_direct_room_visibility_by_you">جعلتَ الرسائل المُستقبلية مرئية لـ %1$s</string>
+    <string name="notice_made_future_direct_room_visibility">جعلَ %1$s الرسائل المُستقبلية مرئية لـ %2$s</string>
     <string name="notice_direct_room_leave_by_you">غادرتَ الغرفة</string>
     <string name="notice_direct_room_leave">غادرَ ⁨%1$s⁩ الغرفة</string>
     <string name="notice_direct_room_join_by_you">انضممت</string>
@@ -177,17 +177,18 @@
     <string name="clear_timeline_send_queue">محو قائمة انتظار الإرسال</string>
     <string name="event_status_sending_message">يجري إرسال الرِّسالة…</string>
     <string name="initial_sync_start_importing_account_data">المُزامنة الأولية:
-\nيجري إستيرد مَعلومات الحِساب</string>
+\nيستورد بيانات الحِساب</string>
     <string name="initial_sync_start_importing_account_groups">المُزامنة الأولية:
-\nيجري إستيرد المُجتمعات</string>
+\nيستورد المُجتمعات</string>
     <string name="initial_sync_start_importing_account_left_rooms">المُزامنة الأولية:
-\nيجري إستيرد الغُرف المُغادَر مِنها</string>
+\nيستورد الغُرف المُغادَر مِنها</string>
     <string name="initial_sync_start_importing_account_invited_rooms">المُزامنة الأولية:
-\nيجري إستيرد الغُرف المَدعو إليها</string>
+\nيستورد الغُرف المَدعو إليها</string>
     <string name="initial_sync_start_importing_account_joined_rooms">المُزامنة الأولية:
-\nيجري إستيرد الغُرف المُنضم فيها</string>
+\nيستورد المحادثات
+\nهذا قد يستغرق بعض الوقت حسب عدد الغرف المنضم إليها</string>
     <string name="initial_sync_start_importing_account_rooms">المُزامنة الأولية:
-\nيجري إستيرد الغُرف</string>
+\nيستورد الغُرف</string>
     <string name="initial_sync_start_importing_account_crypto">المُزامنة الأولية:
 \nيجري إستيرد التَعمية</string>
     <string name="room_displayname_empty_room_was">غُرفة فارِغة (كانت %s)</string>
@@ -1132,10 +1133,10 @@
     <string name="notice_room_canonical_alias_set">غير %1$s عنوان الغرفة الى %2$s.</string>
     <string name="event_status_sent_message">أُرسلت الرسالة</string>
     <string name="initial_sync_start_downloading">المزامنة الأولية:
-\nينزل البيانات…</string>
+\nينزّل البيانات…</string>
     <string name="initial_sync_start_server_computing">المزامنة الأولية:
 \nينتظر رد الخادم…</string>
-    <string name="notice_display_name_set">غير %1$s اسمه الى %2$s</string>
+    <string name="notice_display_name_set">غير %1$s اسمه العلنيّ الى %2$s</string>
     <plurals name="notice_room_aliases_added">
         <item quantity="zero">%1$s أضاف %2$s كعنوان لهذه الغرفة.</item>
         <item quantity="one">%1$s أضاف %2$s كعنوان لهذه الغرفة.</item>
@@ -1330,4 +1331,33 @@
     <string name="keys_backup_setup_step2_text_title">أمّن النسخ الاختياطي بعبارة مرور.</string>
     <string name="keys_backup_setup_step1_manual_export">تصدير المفاتيح يدويًا</string>
     <string name="keys_backup_setup_step1_advanced">(متقدم)</string>
+    <string name="send_bug_report_include_key_share_history">أرسل سجل طلبات مشاركة المفاتيح</string>
+    <string name="audio_meeting">ابدأ مقابلة صوتية</string>
+    <string name="video_meeting">ابدأ مقابلة فيديو</string>
+    <string name="notice_end_to_end_unknown_algorithm">%1$s فعّل تشفير طرف لطرف (لم يُتعرف على خوارزمية %2$s).</string>
+    <string name="notice_end_to_end_ok_by_you">عطلتّ تشفير طرف لطرف.</string>
+    <string name="notice_end_to_end_ok">%1$s فعّل تشفير طرف لطرف.</string>
+    <string name="room_permissions_change_topic">غيّر الموضوع</string>
+    <string name="room_permissions_change_permissions">عدّل الأذونات</string>
+    <string name="room_permissions_change_space_name">غيّر اسم الفضاء</string>
+    <string name="room_permissions_change_room_name">غيّر اسم الغرفة</string>
+    <string name="room_permissions_enable_space_encryption">فعّل تشفير الفضاء</string>
+    <string name="room_permissions_change_main_address_for_the_space">غيّر العنوان الرئيسي للفضاء</string>
+    <string name="room_permissions_change_main_address_for_the_room">غيّر العنوان الرئيسي للغرفة</string>
+    <string name="room_permissions_change_space_avatar">غيّر الصورة الرمزية للفضاء</string>
+    <string name="room_permissions_change_room_avatar">غيّر الصورة الرمزية للغرفة</string>
+    <string name="room_permissions_modify_widgets">عدّل الودجات</string>
+    <string name="room_permissions_notify_everyone">نبّه الكل</string>
+    <string name="room_permissions_remove_messages_sent_by_others">أزل رسائل الآخرين</string>
+    <string name="room_permissions_ban_users">احظر مستخدمين</string>
+    <string name="room_permissions_kick_users">أطرد مستخدمين</string>
+    <string name="room_permissions_change_settings">غيّر الإعدادات</string>
+    <string name="room_permissions_invite_users">أدعوا مستخدمين</string>
+    <string name="room_permissions_send_messages">أرسل رسائل</string>
+    <string name="room_permissions_enable_room_encryption">فعّل تشفير الغرفة</string>
+    <string name="keys_backup_restore_success_title">أُستعيد النسخ الاحتياطي %s !</string>
+    <string name="keys_backup_recovery_code_empty_error_message">رجاءً أدخل مفتاح الاستعادة</string>
+    <string name="keys_backup_unlock_button">فك قفل التأريخ</string>
+    <string name="keys_backup_restoring_importing_keys_waiting_message">يستورد المفاتيح…</string>
+    <string name="keys_backup_restoring_downloading_backup_waiting_message">ينزّل المفاتيح…</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-cs/strings.xml b/vector/src/main/res/values-cs/strings.xml
index 2ddad88550..2817e96ada 100644
--- a/vector/src/main/res/values-cs/strings.xml
+++ b/vector/src/main/res/values-cs/strings.xml
@@ -69,7 +69,8 @@
     <string name="initial_sync_start_importing_account_rooms">Úvodní synchronizace:
 \nImportuji místnosti</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Úvodní synchronizace:
-\nImportuji místností, jichž jste členy</string>
+\nNačítání konverzací
+\nPokud jste se připojili k mnoha místnostem, může to chvíli trvat</string>
     <string name="initial_sync_start_importing_account_left_rooms">Úvodní synchronizace:
 \nImportuji místnost, jež jste opustili</string>
     <string name="initial_sync_start_importing_account_groups">Úvodní synchronizace:
@@ -78,7 +79,7 @@
 \nImportuji data účtu</string>
     <string name="event_status_sending_message">Odesílám zprávu…</string>
     <string name="initial_sync_start_importing_account_invited_rooms">Úvodní synchronizace:
-\nImportuji pozvání</string>
+\nImportuji pozvánky do místností</string>
     <string name="clear_timeline_send_queue">Vymazat frontu neodeslaných zpráv</string>
     <string name="notice_room_invite_with_reason">%1$s pozvali %2$s. Důvod: %3$s</string>
     <string name="notice_room_invite_you_with_reason">%1$s vás pozvali. Důvod: %2$s</string>
@@ -381,7 +382,7 @@
     <string name="read_receipt">Přečíst</string>
     <string name="join_room">Vstoupit do místnosti</string>
     <string name="username">Uživatelské jméno</string>
-    <string name="create_account">Založit účet</string>
+    <string name="create_account">Vytvořit účet</string>
     <string name="login">Přihlásit se</string>
     <string name="logout">Odhlásit se</string>
     <string name="hs_url">Adresa domovského serveru</string>
@@ -587,7 +588,7 @@
     <string name="room_participants_leave_prompt_title">Opustit místnost</string>
     <string name="room_participants_leave_prompt_msg">Opravdu chcete opustit tuto místnost\?</string>
     <string name="room_participants_remove_prompt_msg">Opravdu chcete vyhodit %s z této konverzace\?</string>
-    <string name="room_participants_create">Založit</string>
+    <string name="room_participants_create">Vytvořit</string>
     <string name="room_participants_online">On-line</string>
     <string name="room_participants_offline">Off-line</string>
     <string name="room_participants_idle">Nečinný</string>
@@ -720,7 +721,7 @@
     <string name="room_recents_low_priority">NÍZKÁ PRIORITA</string>
     <string name="room_recents_invites">POZVÁNKY</string>
     <string name="room_recents_start_chat">Začít konverzaci</string>
-    <string name="room_recents_create_room">Založit místnost</string>
+    <string name="room_recents_create_room">Vytvořit místnost</string>
     <string name="room_recents_join_room">Vstoupit do místnosti</string>
     <string name="room_recents_join_room_title">Vstoupit do místnosti</string>
     <string name="room_recents_join_room_prompt">Zadejte ID nebo přezdívku místnosti</string>
@@ -1223,7 +1224,7 @@
     <string name="historical_placeholder">Hledej v minulosti</string>
     <string name="widget_no_power_to_manage">Pro správu widgetů v této místnosti potřebujete oprávnění</string>
     <string name="widget_creation_failure">Založení widgetu se nezdařilo</string>
-    <string name="settings_labs_create_conference_with_jitsi">Založit konferenční hovor s jitsi</string>
+    <string name="settings_labs_create_conference_with_jitsi">Vytvořit konferenční hovor s jitsi</string>
     <string name="widget_delete_message_confirmation">Jste si jisti, že chcete smazat widget z této místnosti\?</string>
     <plurals name="active_widgets">
         <item quantity="one">%d aktivní widget</item>
@@ -1253,7 +1254,7 @@
     <string name="room_widget_webview_access_camera">Použít fotoaparát</string>
     <string name="room_widget_webview_access_microphone">Použít mikrofon</string>
     <string name="room_widget_webview_read_protected_media">Číst media chráněná DRM</string>
-    <string name="widget_integration_unable_to_create">Nelze založit widget.</string>
+    <string name="widget_integration_unable_to_create">Nelze vytvořit widget.</string>
     <string name="widget_integration_failed_to_send_request">Odeslání požadavku selhalo.</string>
     <string name="widget_integration_positive_power_level">Energetická hladina musí být pozitivní celé číslo.</string>
     <string name="widget_integration_must_be_in_room">Nejste v této místnosti.</string>
@@ -1310,8 +1311,8 @@
     <string name="notification_off">Vypnout</string>
     <string name="notification_silent">Tiché</string>
     <string name="notification_noisy">Hlučné</string>
-    <string name="create">Založit</string>
-    <string name="create_community">Založit komunitu</string>
+    <string name="create">Vytvořit</string>
+    <string name="create_community">Vytvořit komunitu</string>
     <string name="community_name">Jméno komunity</string>
     <string name="community_name_hint">Příklad</string>
     <string name="community_id">Id komunity</string>
@@ -1384,7 +1385,7 @@
     <string name="plus_x">+%d</string>
     <string name="x_plus">%d+</string>
     <string name="no_valid_google_play_services_apk">Žádný platný APK Google Plaz Services nenalezen. Oznámení možná nebudou pracovat spolehlivě.</string>
-    <string name="passphrase_create_passphrase">Založit přístupovou frázi</string>
+    <string name="passphrase_create_passphrase">Vytvořit přístupovou frázi</string>
     <string name="passphrase_confirm_passphrase">Potvrdit přístupovou frázi</string>
     <string name="passphrase_enter_passphrase">Zadat přístupovou frázi</string>
     <string name="passphrase_passphrase_does_not_match">Přistupová fráze se neshoduje</string>
@@ -1550,7 +1551,7 @@
     <string name="event_redacted_by_admin_reason">Událost moderována správcem místnosti</string>
     <string name="last_edited_info_message">Naposledy upravil %1$s dne %2$s</string>
     <string name="malformed_message">Nečitelná událost, nelze zobrazit</string>
-    <string name="create_new_room">Založit novou místnost</string>
+    <string name="create_new_room">Vytvořit novou místnost</string>
     <string name="error_no_network">Žádná síť. Prosím, zkontrolujte své spojení do internetu.</string>
     <string name="action_change">Změnit</string>
     <string name="change_room_directory_network">Změnit síť</string>
@@ -1561,7 +1562,7 @@
     <string name="fab_menu_create_room">Místnosti</string>
     <string name="fab_menu_create_chat">Přímé zprávy</string>
     <string name="create_room_title">Nová místnost</string>
-    <string name="create_room_action_create">ZALOŽIT</string>
+    <string name="create_room_action_create">VYTVOŘIT</string>
     <string name="create_room_name_hint">Název</string>
     <string name="create_room_public_title">Veřejná</string>
     <string name="create_room_public_description">Kdokoli smí vstoupit do této místnosti</string>
@@ -1608,7 +1609,7 @@
     <string name="no_message_edits_found">Úpravy nenalezeny</string>
     <string name="room_filtering_filter_hint">Filtrovat konverzace…</string>
     <string name="room_filtering_footer_title">Nemůžete najít, co hledáte\?</string>
-    <string name="room_filtering_footer_create_new_room">Založit novou místnost</string>
+    <string name="room_filtering_footer_create_new_room">Vytvořit novou místnost</string>
     <string name="room_filtering_footer_create_new_direct_message">Poslat novou přímou zprávu</string>
     <string name="room_filtering_footer_open_room_directory">Ukázat adresář místností</string>
     <string name="room_directory_search_hint">Jméno nebo ID (#example:matrix.org)</string>
@@ -1623,7 +1624,7 @@
     <string name="message_view_edit_history">Ukázat historii úprav</string>
     <string name="terms_of_service">Všeobecné podmínky</string>
     <string name="review_terms">Pročíst všeobecné podmínky</string>
-    <string name="terms_description_for_identity_server">Nechte se nalézt druhými</string>
+    <string name="terms_description_for_identity_server">Nechte se najít druhými</string>
     <string name="terms_description_for_integration_manager">Použijte boty, můstky, widgety a nálepkové sady</string>
     <string name="read_at">Čtěte na</string>
     <string name="identity_server">Server pro identity</string>
@@ -1631,11 +1632,11 @@
     <string name="add_identity_server">Nastavit server pro identity</string>
     <string name="change_identity_server">Změnit server pro identity</string>
     <string name="settings_discovery_identity_server_info">Nyní používáte %1$s, abyste nalezli a byli nalezeni existujícími kontakty, které znáte.</string>
-    <string name="settings_discovery_identity_server_info_none">Nyní nepoužíváte server pro identity. Abyste existující známé kontakty nalezli a nechali se jimi nalézt, nastavte nějaký níže.</string>
+    <string name="settings_discovery_identity_server_info_none">Nyní nepoužíváte server pro identity. Abyste známé kontakty našli a nechali se jimi najít, nastavte nějaký níže.</string>
     <string name="settings_discovery_emails_title">Emailová adresa k nalezení</string>
     <string name="settings_discovery_no_mails">Volby pro nalezení se ukážou, jakmile doplníte email.</string>
     <string name="settings_discovery_no_msisdn">Volby pro nalezení se ukážou, jakmile doplníte telefonní číslo.</string>
-    <string name="settings_discovery_disconnect_identity_server_info">Odpojení od serveru identit bude znamenat, že Vás jiní uživatelé nebudou moci nalézt a Vy nebudete moci pozvat druhé pomocí emailu nebo telefonního čísla.</string>
+    <string name="settings_discovery_disconnect_identity_server_info">Odpojení od serveru identit bude znamenat, že Vás jiní uživatelé nebudou moci najít a Vy nebudete moci pozvat druhé pomocí emailu nebo telefonního čísla.</string>
     <string name="settings_discovery_msisdn_title">Telefonní čísla pro nalezení</string>
     <string name="settings_discovery_confirm_mail">Poslali jsme Vám potvrzovací email na %s, podívejte se do emailu a klikněte na protvrzovací odkaz</string>
     <string name="settings_discovery_mail_pending">Nevyřízený</string>
@@ -1655,8 +1656,8 @@
     <string name="a11y_open_drawer">Otevřít navigační zásuvku</string>
     <string name="a11y_create_menu_open">Otevřít menu založení místnosti</string>
     <string name="a11y_create_menu_close">Zavřít menu založení místnosti…</string>
-    <string name="a11y_create_direct_message">Založit novou přímou konverzaci</string>
-    <string name="a11y_create_room">Založit novou místnost</string>
+    <string name="a11y_create_direct_message">Vytvořit novou přímou konverzaci</string>
+    <string name="a11y_create_room">Vytvořit novou místnost</string>
     <string name="a11y_close_keys_backup_banner">Zavřít titulek zálohy klíčů</string>
     <string name="a11y_show_password">Ukázat heslo</string>
     <string name="a11y_hide_password">Skrýt heslo</string>
@@ -1734,7 +1735,7 @@
     <string name="login_connect_to_modular">Připojit k Element Matrix Services</string>
     <string name="login_connect_to_a_custom_server">Upravit připojení k serveru</string>
     <string name="login_signin_to">Přihlásit se na %1$s</string>
-    <string name="login_signup">Založit účet</string>
+    <string name="login_signup">Vytvořit účet</string>
     <string name="login_signin">Přihlásit se</string>
     <string name="login_signin_sso">Pokračovat s SSO</string>
     <string name="login_server_url_form_modular_hint">Adresa Element Matrix Services</string>
@@ -1746,7 +1747,7 @@
 \n
 \nChcete se přihlásit webovým klientem\?</string>
     <string name="login_registration_disabled">Omlouváme se, tento server již nepřijímá nové účty.</string>
-    <string name="login_registration_not_supported">Aplikace nemůže založit účet na tomto domovském serveru.
+    <string name="login_registration_not_supported">Aplikace nemůže vytvořit účet na tomto domovském serveru.
 \n
 \nChcete se přihlásit webovým klientem\?</string>
     <string name="login_login_with_email_error">Tato emailová adresa se nevztahuje k žádnému účtu.</string>
@@ -1916,7 +1917,7 @@
         <item quantity="few">%1$d osoby</item>
         <item quantity="other">%1$d osob</item>
     </plurals>
-    <string name="room_profile_section_more_uploads">Nahrání</string>
+    <string name="room_profile_section_more_uploads">Nahrané</string>
     <string name="room_profile_section_more_leave">Opustit místnost</string>
     <string name="room_profile_leaving_room">Opouštím místnost…</string>
     <string name="room_member_power_level_admins">Správci</string>
@@ -1951,15 +1952,15 @@
     <string name="verification_code_notice">Porovnejte kód s tím na obrazovce druhého uživatele.</string>
     <string name="verification_conclusion_ok_notice">Zprávy s tímto uživatelem jsou koncově šifrovány a nemohou být čteny třetími stranami.</string>
     <string name="verification_conclusion_ok_self_notice">Vaše nová relace je nyní ověřena. Má přístup k Vašim zašifrovaným zprávám a ostatní uživatelé ji uvidi jako důvěryhodnou.</string>
-    <string name="encryption_information_cross_signing_state">Křížový podpis</string>
-    <string name="encryption_information_dg_xsigning_complete">Křížový podpis je zapnut.
+    <string name="encryption_information_cross_signing_state">Křížové podepisování</string>
+    <string name="encryption_information_dg_xsigning_complete">Křížové podpisování je zapnuto.
 \nPrivátní klíče v zařízení.</string>
-    <string name="encryption_information_dg_xsigning_trusted">Křížový podpis je zapnut
+    <string name="encryption_information_dg_xsigning_trusted">Křížové podpisování je zapnuto
 \nKlíče jsou důvěryhodné.
 \nPrivátní klíče nejsou známy</string>
-    <string name="encryption_information_dg_xsigning_not_trusted">Křížový podpis je zapnut.
+    <string name="encryption_information_dg_xsigning_not_trusted">Křížové podpisování je zapnuto.
 \nKlíče nejsou důvěryhodné</string>
-    <string name="encryption_information_dg_xsigning_disabled">Křížový podpis není zapnut</string>
+    <string name="encryption_information_dg_xsigning_disabled">Křížové podpisování není zapnuto</string>
     <string name="settings_active_sessions_list">Aktivní relace</string>
     <string name="settings_active_sessions_show_all">Ukázat všechny relace</string>
     <string name="settings_active_sessions_manage">Správa relací</string>
@@ -2006,7 +2007,7 @@
         <item quantity="other">%d hlasů - Konečné výsledky</item>
     </plurals>
     <string name="poll_item_selected_aria">Zvolená možnost</string>
-    <string name="command_description_poll">Založí jednoduchou anketu</string>
+    <string name="command_description_poll">Vytvoří jednoduché hlasování</string>
     <string name="verification_cannot_access_other_session">Použijte metodu obnovy</string>
     <string name="verification_use_passphrase">Pokud se nemůžete dostat do existující relace</string>
     <string name="new_signin">Nové přihlášení</string>
@@ -2142,19 +2143,19 @@
     <string name="uploads_files_subtitle">%1$s %2$s</string>
     <string name="uploads_files_no_result">V této místnosti nejsou žádné soubory</string>
     <string name="login_connect_using_matrix_id_notice">Jinak, máte-li již účet a znáte-li svůj identifikátor a heslo, můžete použít tuto metodu:</string>
-    <string name="login_connect_using_matrix_id_submit">Přihlásit se s mým identifikátorem Matrixu</string>
+    <string name="login_connect_using_matrix_id_submit">Přihlásit se identifikátorem Matrixu</string>
     <string name="login_signin_matrix_id_title">Přihlásit se</string>
     <string name="login_signin_matrix_id_notice">Pokud založíte účet na domovském serveru, použijte své Matrix ID (např. @user:domain.com) a heslo níže.</string>
     <string name="login_signin_matrix_id_hint">Identifikátor uživatele</string>
     <string name="login_signin_matrix_id_error_invalid_matrix_id">To není platný identifikátor uživatele. Platný formát: \'@uživatel:homeserver.org\'</string>
     <string name="autodiscover_well_known_error">Nemohu najít platný domovský server. Prosím, zkontrolujte svůj identifikátor</string>
     <string name="no_connectivity_to_the_server_indicator_airplane">Režim letadlo je zapnut</string>
-    <string name="template_use_other_session_content_description">Použijte na svých zařízeních nejnovější ${app_name}, ${app_name} Web, ${app_name} Desktop, ${app_name} iOS, ${app_name} pro Android nebo jiný Matrix klient schopný křížového přihlášení</string>
+    <string name="template_use_other_session_content_description">Použijte na svých zařízeních nejnovější ${app_name}, ${app_name} Web, ${app_name} Desktop, ${app_name} iOS, ${app_name} pro Android nebo jiný Matrix klient schopný křížového podepisování</string>
     <string name="template_app_desktop_web">${app_name} Web
 \n${app_name} Desktop</string>
     <string name="template_app_ios_android">${app_name} iOS
 \n${app_name} Android</string>
-    <string name="or_other_mx_capabale_client">nebo jiný Matrix klient schopný křížového přihlášení</string>
+    <string name="or_other_mx_capabale_client">nebo jiný Matrix klient schopný křížového podepisování</string>
     <string name="template_use_latest_app">Použijte na svých zařízeních nejnovější ${app_name}:</string>
     <string name="command_description_discard_session">Vynutí zahození probíhající skupinové relace v šifrované místnosti</string>
     <string name="command_description_discard_session_not_handled">Podporováno jen v šifrovaných místnostech</string>
@@ -2179,7 +2180,7 @@
     <string name="external_link_confirmation_message">Odkaz %1$s Vás převede na jiný site: %2$s.
 \n
 \nOpravdu chcete pokračovat\?</string>
-    <string name="create_room_dm_failure">Nemohli jsme vytvořit Vaši DM. Prosím, zkontrolujte uživatele, které chcete pozvat, a zkuste znovu.</string>
+    <string name="create_room_dm_failure">Nemohli jsme vytvořit vaši přímou zprávu. Prosím, zkontrolujte uživatele, které chcete pozvat, a zkuste znovu.</string>
     <string name="add_members_to_room">Přidat členy</string>
     <string name="invite_users_to_room_action_invite">POZVAT</string>
     <string name="inviting_users_to_room">Zvu uživatele…</string>
@@ -2228,7 +2229,7 @@
     <string name="dialog_title_success">Podařilo se</string>
     <string name="bottom_action_notification">Oznámení</string>
     <string name="template_call_failed_no_connection">Volání ${app_name}u se nezdařilo</string>
-    <string name="call_failed_no_connection_description">Založit spojení v reálném čase se nezdařilo.
+    <string name="call_failed_no_connection_description">Nezdařilo se navázat spojení v reálném čase.
 \nProsím, požádejte správce svého domovského serveru o konfiguraci TURN serveru, aby volání fungovala spolehlivě.</string>
     <string name="call_select_sound_device">Vybrat zvukové zařízení</string>
     <string name="sound_device_phone">Telefon</string>
@@ -2276,7 +2277,7 @@
     <string name="error_threepid_auth_failed">Ujistěte se, že kliknete na odkaz v e-mailu, který jsme Vám poslali.</string>
     <string name="settings_secure_backup_section_title">Bezpečná záloha</string>
     <string name="settings_secure_backup_manage">Správa</string>
-    <string name="settings_secure_backup_setup">Založit bezpečnou zálohu</string>
+    <string name="settings_secure_backup_setup">Vytvořit bezpečnou zálohu</string>
     <string name="settings_secure_backup_reset">Resetovat bezpečnou zálohu</string>
     <string name="settings_secure_backup_enter_to_setup">Nastavit na tomto zařízení</string>
     <string name="settings_secure_backup_section_info">Ochrana před ztrátou přístupu k šifrovaným zprávám a datům pomocí zálohy šifrovacích klíčů na Vašem serveru.</string>
@@ -2402,7 +2403,7 @@
     <string name="auth_pin_forgot">Zapomněli jste PIN\?</string>
     <string name="auth_pin_reset_title">Resetovat PIN</string>
     <string name="auth_pin_new_pin_action">Nový PIN</string>
-    <string name="auth_pin_reset_content">Pro resetování svého PINu se budete muset nově přihlásit a založit nový.</string>
+    <string name="auth_pin_reset_content">Pro resetování svého PINu se budete muset nově přihlásit a vytvořit nový.</string>
     <string name="settings_security_pin_code_title">Zapnout PIN</string>
     <string name="settings_security_pin_code_summary">Chcete-li resetovat svůj PIN, klepněte na Zapomenutý PIN pro odhlášení a resetování.</string>
     <string name="auth_pin_confirm_to_disable_title">Pro vypnutí PINu potvrďte PIN</string>
@@ -2415,7 +2416,7 @@
     </plurals>
     <string name="settings_show_room_member_state_events">Zobrazit stavové události účastníků v místnosti</string>
     <string name="settings_show_room_member_state_events_summary">Zahrnuje události pozvat/vstoupit/opustit/vykopnout/vykázat a změny avatara/veřejného jména.</string>
-    <string name="sent_a_poll">Průzkum</string>
+    <string name="sent_a_poll">Hlasování</string>
     <string name="sent_a_bot_buttons">Tlačítka botů</string>
     <string name="sent_a_reaction">Reagoval(a): %s</string>
     <string name="sent_verification_conclusion">Výsledek ověření</string>
@@ -2526,8 +2527,8 @@
     <string name="hide_advanced">Skrýt pokročilé</string>
     <string name="show_advanced">Ukázat pokročilé</string>
     <string name="attachment_viewer_item_x_of_y">%1$d z %2$d</string>
-    <string name="a11y_create_direct_message_by_mxid">Založit novou přímou konverzaci pomocí Matrix ID</string>
-    <string name="a11y_create_direct_message_by_qr_code">Založit novou přímou konverzaci pomocí skenu QR kódu</string>
+    <string name="a11y_create_direct_message_by_mxid">Vytvořit novou přímou konverzaci pomocí Matrix ID</string>
+    <string name="a11y_create_direct_message_by_qr_code">Vytvořit novou přímou konverzaci pomocí skenu QR kódu</string>
     <string name="identity_server_consent_dialog_content">Abyste nalezli existující kontakty, jež znáte, souhlasíte s odesláním svých kontaktních údajů (telefonní čísla nebo emailové adresy) na nastavený server identit (%1$s)\?
 \n
 \nZa účelem soukromí budou data před odesláním hašována.</string>
@@ -2570,7 +2571,7 @@
     <string name="room_alias_action_publish">Zveřejnit tuto adresu</string>
     <string name="room_alias_local_address_add">Přidat lokální adresu</string>
     <string name="room_alias_local_address_empty">Tato místnost nemá žádné lokální adresy</string>
-    <string name="room_alias_local_address_subtitle">Nastavte adresy pro tuto místnost, aby uživatelé mohli tuto místnost nalézt přes Váš domovský server (%1$s)</string>
+    <string name="room_alias_local_address_subtitle">Nastavte adresy pro tuto místnost, aby uživatelé mohli tuto místnost najít přes Váš domovský server (%1$s)</string>
     <string name="room_alias_local_address_title">Lokální adresa</string>
     <string name="room_alias_address_hint">Nová zveřejněná adresa (např. #alias:server)</string>
     <string name="room_alias_address_empty">Zatím žádné zveřejněné adresy.</string>
@@ -2750,7 +2751,7 @@
 \nZkuste znovu později nebo se obraťte na správce místnosti, máte-li přístup.</string>
     <string name="join_anyway">I tak vstoupit</string>
     <string name="join_space">Vstoupit do prostoru</string>
-    <string name="create_space">Založit prostor</string>
+    <string name="create_space">Vytvořit prostor</string>
     <string name="skip_for_now">Nyní přeskočit</string>
     <string name="share_space_link_message">Připojte se k mému prostoru %1$s %2$s</string>
     <string name="invite_just_to_this_room_desc">Nebudou součástí %s</string>
@@ -2770,7 +2771,7 @@
     <string name="create_spaces_room_public_header">Jaké diskuse si přejete vést v %s\?</string>
     <string name="create_space_error_empty_field_space_name">Dejte prostoru jméno a pokračujte.</string>
     <string name="create_spaces_details_public_header">Doplňte nějaké podrobnosti, aby zaujal. Můžete je kdykoli změnit.</string>
-    <string name="activity_create_space_title">Založit prostor</string>
+    <string name="activity_create_space_title">Vytvořit prostor</string>
     <string name="space_type_private_desc">Pouze na pozvání, nejlepší pro Vás nebo týmy</string>
     <string name="space_type_private">Privátní</string>
     <string name="space_type_public_desc">Otevřený pro všechny, nejlepší pro komunity</string>
@@ -2783,19 +2784,19 @@
     <string name="create_spaces_who_are_you_working_with">S kým pracujete\?</string>
     <string name="create_spaces_join_info_help">Ke vstupu do existujícího prostoru potřebujete pozvání.</string>
     <string name="create_spaces_you_can_change_later">Můžete změnit později</string>
-    <string name="create_spaces_choose_type_label">Jaký typ prostoru chcete založit\?</string>
+    <string name="create_spaces_choose_type_label">Jaký typ prostoru chcete vytvořit\?</string>
     <string name="your_private_space">Váš privátní prostor</string>
     <string name="your_public_space">Váš veřejný prostor</string>
     <string name="add_space">Přidat prostor</string>
     <string name="command_description_leave_room">Opustit místnost s daným id (nebo nynější místnost pokud prázdné)</string>
     <string name="command_description_join_space">Vstoupit do prostoru s daným id</string>
-    <string name="command_description_create_space">Založit prostor</string>
+    <string name="command_description_create_space">Vytvořit prostor</string>
     <string name="search_hint_room_name">Hledat jméno</string>
-    <string name="room_settings_room_access_restricted_description">Kdokoli v prostoru s touto místností ji může nalézt a vstoupit. Jen správci místnosti ji mohou připojit k prostoru.</string>
+    <string name="room_settings_room_access_restricted_description">Kdokoli v prostoru s touto místností ji může najít a vstoupit do ní. Do prostoru ji mohou připojit jen správci místnosti.</string>
     <string name="room_settings_room_access_restricted_title">Pouze členové prostoru</string>
-    <string name="room_settings_room_access_public_description">Kdokoli může místnost nalézt a vstoupit</string>
-    <string name="room_settings_room_access_public_title">Veřejná</string>
-    <string name="room_settings_room_access_private_description">Pouze pozvaní mohou místnost nalézt a vstoupit</string>
+    <string name="room_settings_room_access_public_description">Kdokoliv může místnost najít a připojit se do ní</string>
+    <string name="room_settings_room_access_public_title">Veřejný</string>
+    <string name="room_settings_room_access_private_description">Pouze pozvaní mohou místnost najít a vstoupit do ní</string>
     <string name="room_settings_room_access_private_title">Privátní</string>
     <string name="room_settings_room_access_entry_unknown">Neznámé nastavení přístupu (%s)</string>
     <string name="room_settings_room_access_entry_knock">Každý může na místnost zaklepat, členové pak mohou přijmout či odmítnout</string>
@@ -2930,7 +2931,7 @@
     <string name="spaces_which_can_access">Prostory, které mají přístup</string>
     <string name="allow_space_member_to_find_and_access">Umožněte členům prostoru ho najít a zpřístupnit.</string>
     <string name="room_create_member_of_space_name_can_join">Členové prostoru %s mohou vyhledávat, prohlížet a připojovat se.</string>
-    <string name="room_settings_room_access_private_invite_only_title">Soukromé (pouze pro pozvané)</string>
+    <string name="room_settings_room_access_private_invite_only_title">Soukromý (pouze pro pozvané)</string>
     <string name="denied_permission_voice_message">Chcete-li odesílat hlasové zprávy, povolte oprávnění mikrofonu.</string>
     <string name="settings_room_upgrades">Aktualizace místnosti</string>
     <string name="settings_messages_by_bot">Zprávy od bota</string>
@@ -3061,4 +3062,7 @@
     <string name="a11y_presence_unavailable">Nedostupný</string>
     <string name="a11y_presence_offline">Offline</string>
     <string name="a11y_presence_online">Online</string>
+    <string name="notification_listening_for_notifications">Naslouchání oznámením</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Vyberte domovský server</string>
+    <string name="login_error_homeserver_from_url_not_found">Nelze se spojit s domovským serverem na adrese %s. Zkontrolujte prosím svůj odkaz nebo vyberte domovský server ručně.</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-da/strings.xml b/vector/src/main/res/values-da/strings.xml
index c6c854a128..077bf0efda 100644
--- a/vector/src/main/res/values-da/strings.xml
+++ b/vector/src/main/res/values-da/strings.xml
@@ -541,4 +541,5 @@ Er du sikker?</string>
     <string name="summary_you_sent_sticker">Du har sendt et klistermærke.</string>
     <string name="summary_user_sent_sticker">%1$s har sendt et klistermærke.</string>
     <string name="summary_you_sent_image">Du har sendt et billede.</string>
+    <string name="link_this_email_settings_link">Forbind denne email med din konto</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-de/strings.xml b/vector/src/main/res/values-de/strings.xml
index 8a22a43b06..fe4257da79 100644
--- a/vector/src/main/res/values-de/strings.xml
+++ b/vector/src/main/res/values-de/strings.xml
@@ -1072,7 +1072,7 @@
     <string name="command_description_op_user">Bestimmt das Berechtigungslevel des Benutzers</string>
     <string name="command_description_deop_user">Setzt Berechtigungen des Benutzers zurück</string>
     <string name="command_description_invite_user">Lädt Benutzer mit angegebener Kennung in den aktuellen Raum ein</string>
-    <string name="command_description_join_room">Tritt dem Raum mit angegebenen Alias bei</string>
+    <string name="command_description_join_room">Raum mit angegebener Adresse beitreten</string>
     <string name="command_description_part_room">Verlasse Raum</string>
     <string name="command_description_topic">Raumthema ändern</string>
     <string name="command_description_kick_user">Entfernt die Person angegebener ID</string>
@@ -1741,7 +1741,7 @@
     <string name="timeline_unread_messages">Ungelesene Nachrichten</string>
     <string name="login_splash_text1">Privat oder in Gruppen mit Leuten chatten</string>
     <string name="login_splash_text2">Halte Gespräche mittels Verschlüsselung privat</string>
-    <string name="login_splash_submit">Beginne</string>
+    <string name="login_splash_submit">Los geht\'s</string>
     <string name="login_server_title">Wähle einen Server</string>
     <string name="login_server_text">Genau wie bei E-Mails haben Accounts ein Zuhause, auch wenn du mit jedem kommunizieren kannst</string>
     <string name="login_server_matrix_org_text">Folge Millionen Anderen kostenlos auf dem größten öffentlichen Server</string>
@@ -1755,7 +1755,7 @@
     <string name="settings_agree_to_terms">Stimme den Nutzungsbedingungen des Identitätsservers (%s) zu, um zu erlauben per E-Mail oder Telefonnummer gefunden zu werden.</string>
     <string name="error_handling_incoming_share">Zu teilende Daten nicht verarbeitbar</string>
     <string name="login_splash_text3">Erweitere &amp; individualisiere dein Benutzererlebnis</string>
-    <string name="login_connect_to">Verbinde mit %1$s</string>
+    <string name="login_connect_to">Mit %1$s verbinden</string>
     <string name="login_connect_to_modular">Mit Element Matrix Services verbinden</string>
     <string name="login_connect_to_a_custom_server">Mit einem benutzerdefinierten Server verbinden</string>
     <string name="login_signin_to">Bei %1$s anmelden</string>
@@ -1818,7 +1818,7 @@
     <string name="login_mode_not_supported">Die Anwendung kann sich nicht bei diesem Home-Server anmelden. Der Home-Server unterstützt die folgenden Anmeldetypen: %1$s.
 \n 
 \nMöchtest du dich mit einem Webclient anmelden\?</string>
-    <string name="login_reset_password_notice">Eine Bestätigungsmail wird an dich gesendet, um dein neues Passwort zu bestätigen.</string>
+    <string name="login_reset_password_notice">Dir wird eine Bestätigungsmail gesendet, um dein neues Passwort zu bestätigen.</string>
     <string name="login_reset_password_submit">Weiter</string>
     <string name="login_reset_password_success_notice_2">Du wurdest von allen Sitzungen abgemeldet und erhältst keine Push-Benachrichtigungen mehr. Um Benachrichtigungen wieder zu aktivieren, melde dich auf jedem Gerät erneut an.</string>
     <string name="login_reset_password_cancel_confirmation_title">Warnung</string>
@@ -1831,7 +1831,7 @@
     <string name="login_msisdn_confirm_submit">Weiter</string>
     <string name="login_msisdn_error_not_international">Internationale Telefonnummern müssen mit \'+\' beginnen</string>
     <string name="login_msisdn_error_other">Die Telefonnummer scheint ungültig zu sein. Bitte prüfen</string>
-    <string name="login_signup_to">Anmelden bei %1$s</string>
+    <string name="login_signup_to">Registrieren bei %1$s</string>
     <string name="login_signup_username_hint">Benutzername</string>
     <string name="login_signup_submit">Weiter</string>
     <string name="login_signup_cancel_confirmation_title">Warnung</string>
@@ -1949,8 +1949,8 @@
     <string name="room_profile_section_more_leave">Raum verlassen</string>
     <string name="room_profile_leaving_room">Verlasse den Raum…</string>
     <string name="room_member_power_level_admins">Administratoren</string>
-    <string name="room_member_power_level_moderators">Moderierende</string>
-    <string name="room_member_power_level_custom">benutzerdefiniert</string>
+    <string name="room_member_power_level_moderators">Moderatoren</string>
+    <string name="room_member_power_level_custom">Benutzerdefiniert</string>
     <string name="room_member_power_level_invites">Eingeladen</string>
     <string name="room_member_power_level_users">Nutzer</string>
     <string name="room_member_power_level_admin_in">Admin in %1$s</string>
@@ -2175,7 +2175,7 @@
     <string name="verify_other_sessions">Verifiziere alle deine Sitzungen, um sicherzustellen, dass dein Konto &amp; deine Nachrichten sicher sind</string>
     <string name="verify_this_session">Bestätige neue Anmeldung zu deinem Konto: %1$s</string>
     <string name="cross_signing_verify_by_text">Verifiziere manuell mit einem Text</string>
-    <string name="crosssigning_verify_session">Verifiziere Anmeldung</string>
+    <string name="crosssigning_verify_session">Anmeldung verifizieren</string>
     <string name="cross_signing_verify_by_emoji">Verifiziere interaktiv mit Emojis</string>
     <string name="confirm_your_identity">Bestätige deine Identität, indem du diesen Login von einer deiner anderen Sitzungen verifizierst, um Zugriff auf deine verschlüsselten Nachrichten zu erhalten.</string>
     <string name="mark_as_verified">Als vertraut markieren</string>
@@ -2313,7 +2313,7 @@
     <string name="identity_server_error_terms_not_signed">Bitte akzeptiere zuerst die AGB des Identitätsservers in den Einstellungen.</string>
     <string name="template_identity_server_error_bulk_sha256_not_supported">Deiner Privatsphäre wegen unterstützt ${app_name} nur das Senden gehashter E-Mail-Adressen und Telefonnummern.</string>
     <string name="identity_server_error_binding_error">Die Assoziierung ist fehlgeschlagen.</string>
-    <string name="identity_server_error_no_current_binding_error">Für diese Kennung gibt es aktuell keine Assoziierung.</string>
+    <string name="identity_server_error_no_current_binding_error">Für diese Kennung gibt es aktuell keine Zuordnung.</string>
     <string name="identity_server_set_default_notice">Dein Home-Server (%1$s) schlägt %2$s als Identitätsserver vor</string>
     <string name="identity_server_set_default_submit">Benutze %1$s</string>
     <string name="identity_server_set_alternative_notice">Alternativ kannst du die URL eines beliebigen anderen Identitätsservers angeben</string>
@@ -2620,7 +2620,7 @@
     <string name="default_message_emote_confetti">Sendet Konfetti 🎉</string>
     <string name="command_snow">Nachricht mit Schnee senden</string>
     <string name="command_confetti">Sendet die nachfolgende Nachricht mit Konfetti</string>
-    <string name="login_clear_homeserver_history">Nachrichtenverlauf bereinigen</string>
+    <string name="login_clear_homeserver_history">Verlauf löschen</string>
     <string name="login_social_sso">Einmalanmeldung</string>
     <string name="login_social_signin_with">Anmelden mit %s</string>
     <string name="login_social_signup_with">Registrieren mit %s</string>
@@ -2658,7 +2658,7 @@
     <string name="call_tile_call_back">Zurückrufen</string>
     <string name="call_tile_ended">Dieser Anruf wurde beendet</string>
     <string name="call_tile_other_declined">%1$s hat diesen Anruf abgelehnt</string>
-    <string name="call_tile_you_declined">Du hast diesen Anruf %1$s abgelehnt</string>
+    <string name="call_tile_you_declined">Du hast diesen Anruf %s abgelehnt</string>
     <string name="call_tile_in_call">Du nimmst zur Zeit an diesem Anruf teil</string>
     <string name="call_tile_other_started_call">%1$s hat einen Anruf gestartet</string>
     <string name="call_tile_you_started_call">Du hast einen Anruf gestartet</string>
@@ -2696,7 +2696,7 @@
     <string name="a11y_trust_level_default">Standard-Vertrauensstufe</string>
     <string name="a11y_selected">Ausgewählt</string>
     <string name="a11y_video">Video</string>
-    <string name="a11y_unsent_draft">Dieser Raum enthält einen ungesendeten Entwurf</string>
+    <string name="a11y_unsent_draft">enthält einen ungesendeten Entwurf</string>
     <string name="a11y_error_some_message_not_sent">Einige Nachrichten wurden nicht gesendet</string>
     <string name="a11y_delete_avatar">Avatar löschen</string>
     <string name="a11y_change_avatar">Avatar ändern</string>
@@ -2800,7 +2800,7 @@
     <string name="activity_create_space_title">Einen Space erstellen</string>
     <string name="create_spaces_just_me">Nur für mich</string>
     <string name="create_spaces_choose_type_label">Welche Art von Space möchtest du erstellen\?</string>
-    <string name="add_space">Space hinzufügen</string>
+    <string name="add_space">Space erstellen</string>
     <string name="command_description_create_space">Space erstellen</string>
     <string name="room_settings_room_access_restricted_description">Jeder, der sich in einem Space mit diesem Raum befindet, kann diesen Raum finden und ihm beitreten. Nur die Administratoren des Raums können diesen zu einem Space hinzufügen.</string>
     <string name="room_settings_room_access_restricted_title">Nur Space-Mitglieder</string>
@@ -2846,8 +2846,8 @@
     <string name="spaces_no_server_support_description">Für weitere Infos kontaktiere bitte die Administration des Homeservers</string>
     <string name="spaces_no_server_support_title">Dein Homeserver scheint Spaces noch nicht zu unterstützen</string>
     <string name="space_add_rooms">Räume hinzufügen</string>
-    <string name="space_leave_prompt_msg_as_admin">Du bist der Admin von diesem Space. Stelle vor dem Verlassen sicher, dass du die Adminrechte an jemand anderen übergibst.</string>
-    <string name="space_leave_prompt_msg_private">Dieser Raum ist nicht öffentlich. Du wirst ihn ohne Einladung nicht wieder betreten können.</string>
+    <string name="space_leave_prompt_msg_as_admin">Du bist der einzige Admin von diesem Space. Wenn du ihn verlässt, hat niemand Kontrolle über ihn.</string>
+    <string name="space_leave_prompt_msg_private">Du wirst diesen Raum ohne erneute Einladung nicht betreten können.</string>
     <string name="space_leave_prompt_msg_only_you">Du bist die einzige Person hier. Wenn du den Space verlässt, ist er für immer verloren (eine lange Zeit).</string>
     <string name="invite_to_space">Einladen in %s</string>
     <string name="private_space">Privater Space</string>
@@ -2891,12 +2891,12 @@
     <string name="voice_message_tap_to_stop_toast">Klicke, um die Aufnahme zu starten oder stoppen</string>
     <string name="voice_message_n_seconds_warning_toast">%1$ds übrig</string>
     <string name="voice_message_release_to_send_toast">Zum Aufnehmen drücken, zum Senden loslassen</string>
-    <string name="a11y_delete_recorded_voice_message">Aufgenommene Sprachnachricht löschen</string>
+    <string name="a11y_delete_recorded_voice_message">Aufnahme löschen</string>
     <string name="a11y_recording_voice_message">Sprachnachricht wird aufgenommen</string>
     <string name="a11y_pause_voice_message">Sprachnachricht pausieren</string>
     <string name="a11y_play_voice_message">Sprachnachricht abspielen</string>
     <string name="a11y_lock_voice_message">Sprachnachricht einrasten</string>
-    <string name="a11y_start_voice_message">Sprachnachricht starten</string>
+    <string name="a11y_start_voice_message">Sprachnachricht aufnehmen</string>
     <string name="room_using_unstable_room_version">Dieser Raum verwendet die Raumversion %s, die von diesem Heimserver als instabil markiert ist.</string>
     <string name="upgrade_room_no_power_to_manage">Du benötigst die Berechtigung, um einen Raum upzugraden</string>
     <string name="upgrade_room_update_parent_space">Übergeordneten Space automatisch updaten</string>
@@ -3027,4 +3027,25 @@
     <string name="space_participants_kick_prompt_msg">Kicken entfernt die Person aus dem Space
 \n
 \nUm sie für immer zu entfernen, solltest du sie bannen.</string>
+    <string name="a11y_stop_voice_message">Aufnahme beenden</string>
+    <string name="pick_tings_to_leave">Welche Räume willst du verlassen\?</string>
+    <string name="finish_setup">Einrichtung beenden</string>
+    <string name="a11y_presence_unavailable">Nicht verfügbar</string>
+    <string name="a11y_presence_offline">Offline</string>
+    <string name="a11y_presence_online">Online</string>
+    <string name="call_tap_to_return">%1$s Klicke zum Zurückkehren</string>
+    <string name="call_tile_no_answer">Nicht erreicht</string>
+    <string name="command_description_lenny">Nachricht mit ( ͡° ͜ʖ ͡°) beginnen</string>
+    <string name="command_description_whois">Zeigt Information über die Person an</string>
+    <string name="command_description_avatar_for_room">Ändert dein Profilbild im aktuellen Raum</string>
+    <string name="command_description_room_avatar">Ändert das Raumbild</string>
+    <string name="command_description_nick_for_room">Ändert deinen Nicknamen für diesen Raum</string>
+    <string name="command_description_room_name">Ändert den Raumnamen</string>
+    <string name="command_description_unignore_user">Entblockt eine Person und zeigt deren Nachrichten wieder an</string>
+    <string name="command_description_ignore_user">Blockiert eine Person und versteckt deren Nachrichten</string>
+    <string name="room_settings_space_access_public_description">Jeder kann den Space finden und beitreten</string>
+    <string name="room_settings_room_notifications_manage_notifications">Du kannst deine Benachrichtigungen in den %1$s verwalten.</string>
+    <string name="room_settings_room_notifications_encryption_notice">Beachte, dass Benachrichtigungen zu Erwähnungen und Schlüsselwörtern in verschlüsselten Räumen momentan nicht verfügbar sind.</string>
+    <string name="space_permissions_notice">Wähle die Berechtigungen der Rollen aus</string>
+    <string name="space_settings_permissions_subtitle">Rollen deren Berechtigungen einsehen und bearbeiten.</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-et/strings.xml b/vector/src/main/res/values-et/strings.xml
index 99fbf80b3f..f705c497e5 100644
--- a/vector/src/main/res/values-et/strings.xml
+++ b/vector/src/main/res/values-et/strings.xml
@@ -61,21 +61,22 @@
         <item quantity="other">%1$s ja %2$d muud</item>
     </plurals>
     <string name="room_displayname_empty_room">Tühi jututuba</string>
-    <string name="initial_sync_start_importing_account">Alglaadimine:
+    <string name="initial_sync_start_importing_account">Esmane laadimine:
 \nImpordin kontot…</string>
-    <string name="initial_sync_start_importing_account_crypto">Alglaadimine:
+    <string name="initial_sync_start_importing_account_crypto">Esmane laadimine:
 \nImpordin krüptoseadistusi</string>
-    <string name="initial_sync_start_importing_account_rooms">Alglaadimine:
+    <string name="initial_sync_start_importing_account_rooms">Esmane laadimine:
 \nImpordin jututubasid</string>
-    <string name="initial_sync_start_importing_account_joined_rooms">Alglaadimine:
-\nImpordin liitutud jututubasid</string>
-    <string name="initial_sync_start_importing_account_invited_rooms">Alglaadimine:
+    <string name="initial_sync_start_importing_account_joined_rooms">Esmane laadimine:
+\nLaadin sinu vestluste ja jtututubade andmeid
+\nKui sa oled liitunud paljude jututubadega, siis kulub natuke aega</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Esmane laadimine:
 \nImpordin kutsutud jututubasid</string>
-    <string name="initial_sync_start_importing_account_left_rooms">Alglaadimine:
+    <string name="initial_sync_start_importing_account_left_rooms">Esmane laadimine:
 \nImpordin lahkutud jututubasid</string>
-    <string name="initial_sync_start_importing_account_groups">Alglaadimine:
+    <string name="initial_sync_start_importing_account_groups">Esmane laadimine:
 \nImpordin kogukondi</string>
-    <string name="initial_sync_start_importing_account_data">Alglaadimine:
+    <string name="initial_sync_start_importing_account_data">Esmane laadimine:
 \nImpordin kontoandmeid</string>
     <string name="event_status_sending_message">Saadan sõnumit…</string>
     <string name="clear_timeline_send_queue">Tühjenda saatmisjärjekord</string>
@@ -3005,4 +3006,7 @@
     <string name="a11y_presence_unavailable">Pole leitav</string>
     <string name="a11y_presence_offline">Võrgust väljas</string>
     <string name="a11y_presence_online">Võrgus</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Vali koduserver</string>
+    <string name="login_error_homeserver_from_url_not_found">Ei õnnestu ühendus koduserveriga aadressil %s. Palun kontrolli kas link on õige või lisa koduserver käsitsi.</string>
+    <string name="notification_listening_for_notifications">Vaatan, kas leidub teavitusi</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-fa/strings.xml b/vector/src/main/res/values-fa/strings.xml
index ea798cac52..f99084811e 100644
--- a/vector/src/main/res/values-fa/strings.xml
+++ b/vector/src/main/res/values-fa/strings.xml
@@ -62,21 +62,22 @@
     </plurals>
     <string name="room_displayname_empty_room">اتاق خالی</string>
     <string name="initial_sync_start_importing_account">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی حساب…</string>
+\nدرون‌ریزی حساب…</string>
     <string name="initial_sync_start_importing_account_crypto">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی رمزنگاری</string>
+\nدرون‌ریزی رمزنگاری</string>
     <string name="initial_sync_start_importing_account_rooms">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی اتاق‌ها</string>
+\nدرون‌ریزی اتاق‌ها</string>
     <string name="initial_sync_start_importing_account_joined_rooms">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی اتاق‌های پیوسته</string>
+\nبار کردن گفت‌وگوهایتان
+\nاگر به اتاق‌های زیادی پیوسته‌اید، ممکن است کمی طول بکشد</string>
     <string name="initial_sync_start_importing_account_invited_rooms">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی اتاق‌های دعوت‌شده</string>
+\nدرون‌ریزی اتاق‌های دعوت‌شده</string>
     <string name="initial_sync_start_importing_account_left_rooms">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی اتاق‌های ترک‌شده</string>
+\nدرون‌ریزی اتاق‌های ترک شده</string>
     <string name="initial_sync_start_importing_account_groups">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی انجمن‌ها</string>
+\nدرون‌ریزی اجتماع‌ها</string>
     <string name="initial_sync_start_importing_account_data">همگام‌سازی نخستین:
-\nدر حال درون‌ریزی داده‌های حساب</string>
+\nدرون‌ریزی داده‌های حساب</string>
     <string name="event_status_sending_message">در حال فرستادن پیام…</string>
     <string name="clear_timeline_send_queue">پاک‌سازی صفِ در حال ارسال</string>
     <string name="notice_room_invite_no_invitee_with_reason">دعوت %1$s. دلیل: %2$s</string>
@@ -2260,7 +2261,7 @@
     <string name="command_description_kick_user">اخراج کاربر با شناسه داده شده</string>
     <string name="command_description_topic">تنظیم موضوع اتاق</string>
     <string name="command_description_part_room">ترک اتاق</string>
-    <string name="command_description_join_room">با نام مستعار داده‌شده به اتاق بپیوندید</string>
+    <string name="command_description_join_room">به اتاق با نشانی داده شده می‌پیوندد</string>
     <string name="command_description_invite_user">کاربر با شناسه داده شده را به این اتاق دعوت می کند</string>
     <string name="command_description_deop_user">کاربر با شناسه داده شده را غیر‌فعال می‌کند</string>
     <string name="command_description_op_user">سطح قدرت کاربر را تعریف می‌کند</string>
@@ -2633,7 +2634,7 @@
         <item quantity="one">%1$s یک نشانی جایگزین %2$s را برای این اتاق اضافه کرد.</item>
         <item quantity="other">%1$s نشانی‌های جایگزین %2$s را برای این اتاق اضافه کرد.</item>
     </plurals>
-    <string name="initial_sync_start_downloading">همگام‌سازی اولیه:
+    <string name="initial_sync_start_downloading">همگام‌سازی نخستین:
 \nبارگیری داده‌ها…</string>
     <string name="initial_sync_start_server_computing">همگام‌سازی نخستین:
 \nمنتظر پاسخ کارساز…</string>
@@ -3005,4 +3006,7 @@
     <string name="a11y_presence_unavailable">ناموجود</string>
     <string name="a11y_presence_offline">برون‌خط</string>
     <string name="a11y_presence_online">برخط</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">گزینش کارساز خانگی</string>
+    <string name="login_error_homeserver_from_url_not_found">نتوانست در نشانی %s به کارساز خاتگی‌ای برسد. لطفاً پیوندتان را بررسی کرده یا کارساز خانگی‌ای را به صورت دستی برگزینید.</string>
+    <string name="notification_listening_for_notifications">شنود کردن برای آگاهی‌ها</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-fr/strings.xml b/vector/src/main/res/values-fr/strings.xml
index 18a0030939..87f138f245 100644
--- a/vector/src/main/res/values-fr/strings.xml
+++ b/vector/src/main/res/values-fr/strings.xml
@@ -68,7 +68,8 @@
     <string name="initial_sync_start_importing_account_rooms">Synchronisation initiale :
 \nImportation des salons</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Synchronisation initiale :
-\nImportation des salons que vous avez rejoints</string>
+\nChargement des conversations
+\nCela peut prendre du temps si vous avez rejoint beaucoup de salons</string>
     <string name="initial_sync_start_importing_account_invited_rooms">Synchronisation initiale :
 \nImportation des salons où vous avez été invité</string>
     <string name="initial_sync_start_importing_account_left_rooms">Synchronisation initiale :
@@ -3012,4 +3013,7 @@
     <string name="a11y_presence_unavailable">Indisponible</string>
     <string name="a11y_presence_offline">Hors ligne</string>
     <string name="a11y_presence_online">En ligne</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Choisir un serveur d’accueil</string>
+    <string name="login_error_homeserver_from_url_not_found">Impossible de contacter un serveur d’accueil à l’URL %s. Veuillez vérifier votre lien ou choisir manuellement un serveur d’accueil.</string>
+    <string name="notification_listening_for_notifications">Écoute des notifications</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-fy/strings.xml b/vector/src/main/res/values-fy/strings.xml
index 0e31fcbd00..a542951669 100644
--- a/vector/src/main/res/values-fy/strings.xml
+++ b/vector/src/main/res/values-fy/strings.xml
@@ -4,7 +4,7 @@
     <string name="dark_theme">Donker tema</string>
     <string name="black_theme">Swart tema</string>
     <string name="notification_sync_init">Tsjinst wurdt inisjalisearre</string>
-    <string name="notification_sync_in_progress">Syngronisearje…</string>
+    <string name="notification_sync_in_progress">Syngronisaasje…</string>
     <string name="notification_listening_for_events">Lústerje nei barrens</string>
     <string name="notification_noisy_notifications">Lûdsmeldingen</string>
     <string name="notification_silent_notifications">Stille meldingen</string>
@@ -20,15 +20,15 @@
     <string name="title_activity_keys_backup_restore">Kaaireservekopy brûke</string>
     <string name="title_activity_verify_device">Apparaat ferifiearje</string>
     <string name="keys_backup_is_not_finished_please_wait">Kaaireservekopy is noch net ree, in amerijke…</string>
-    <string name="sign_out_bottom_sheet_warning_no_backup">As jo jo no ôfmelde, sille jo jo fersifere berjochten kwytreitsje</string>
-    <string name="sign_out_bottom_sheet_warning_backing_up">Kaaireservekopy is dwaande. Asto dy no ôfmeldst, silsto de tagong ta dyn fersifere berjochten kwytreitsje.</string>
-    <string name="sign_out_bottom_sheet_warning_backup_not_active">Feilige kaaireservekopy moat op al dyn apparaten aktyf wêze om de tagong ta dyn fersifere berjochten net kwyt te reitsjen.</string>
+    <string name="sign_out_bottom_sheet_warning_no_backup">As jo no ôfmelde, sille jo de fersifere berjochten kwytreitsje</string>
+    <string name="sign_out_bottom_sheet_warning_backing_up">Kaaireservekopy is dwaande. As jo no ôfmelde, sille jo de tagong ta jo fersifere berjochten kwytreitsje.</string>
+    <string name="sign_out_bottom_sheet_warning_backup_not_active">Feilige kaaireservekopy moat op al jo apparaten aktyf wêze om de tagong ta jo fersifere berjochten net kwyt te reitsjen.</string>
     <string name="sign_out_bottom_sheet_dont_want_secure_messages">Ik wol myn fersifere berjochten net</string>
     <string name="sign_out_bottom_sheet_backing_up_keys">Reservekopy fan kaaien wurdt makke…</string>
     <string name="keys_backup_activate">Kaaireservekopy brûke</string>
     <string name="are_you_sure">Binne jo wis\?</string>
     <string name="backup">Reservekopy meitsje</string>
-    <string name="sign_out_bottom_sheet_will_lose_secure_messages">Do silst de tagong ta dyn fersifere berjochten ferlieze, útsein asto earst in reservekopy fan dyn kaaien makkest eardatsto dy ôfmeldst.</string>
+    <string name="sign_out_bottom_sheet_will_lose_secure_messages">Jo sille de tagong ta jo fersifere berjochten ferlieze, útsein as jo earst in reservekopy fan jo kaaien meitsje eardat jo ôfmelde.</string>
     <string name="dialog_title_third_party_licences">Lisinsjes fan tredde partijen</string>
     <string name="loading">Lade…</string>
     <string name="ok">OK</string>
@@ -55,15 +55,15 @@
     <string name="revoke">Ynlûke</string>
     <string name="disconnect">Ferbining ferbrekke</string>
     <string name="report_content">Ynhâld melde</string>
-    <string name="active_call">Aktive petear</string>
-    <string name="ongoing_conference_call">Rinnend gearkomstpetear. 
-\nNim diel mei %1$s of %2$s</string>
+    <string name="active_call">Aktive oprop</string>
+    <string name="ongoing_conference_call">Rinnend gearkomstpetear.
+\nDielnimme mei %1$s of %2$s</string>
     <string name="ongoing_conference_call_voice">mikrofoan</string>
     <string name="ongoing_conference_call_video">kamera</string>
     <string name="cannot_start_call">Kin de oprop net starte, probearje it letter nochris</string>
     <string name="missing_permissions_warning">Guon funksjes binne miskien ôfwêzich fanwegen ûntbrekkende rjochten…</string>
     <string name="missing_permissions_error">Dizze aksje is net mooglik fanwegen ûntbrekkende rjochten.</string>
-    <string name="missing_permissions_to_start_conf_call">Om in gearkomst yn dit groepspetear te starten hasto útnûgingsrjochten nedich</string>
+    <string name="missing_permissions_to_start_conf_call">Om in gearkomst yn dit groepspetear te starten hawwe jo útnûgingsrjochten nedich</string>
     <string name="missing_permissions_title_to_start_conf_call">Kin de oprop net starte</string>
     <string name="device_information">Apparaatynformaasje</string>
     <string name="room_no_conference_call_in_encrypted_rooms">Gearkomstpetearen wurde net stipe yn fersifere petearen</string>
@@ -82,7 +82,7 @@
     <string name="action_exit">Ofslute</string>
     <string name="actions">Aksjes</string>
     <string name="action_sign_out">Ofmelde</string>
-    <string name="action_sign_out_confirmation_simple">Binne jo wis dat jo jo ôfmelde wolle\?</string>
+    <string name="action_sign_out_confirmation_simple">Binne jo wis dat jo ôfmelde wolle\?</string>
     <string name="action_voice_call">Spraakoprop</string>
     <string name="action_video_call">Fideo-oprop</string>
     <string name="action_global_search">Globaal sykje</string>
@@ -97,9 +97,9 @@
     <string name="dialog_title_confirmation">Befêstiging</string>
     <string name="dialog_title_warning">Warskôging</string>
     <string name="dialog_title_error">Flater</string>
-    <string name="bottom_action_home">Start</string>
+    <string name="bottom_action_home">Startskerm</string>
     <string name="bottom_action_favourites">Favoriten</string>
-    <string name="bottom_action_people">Minsken</string>
+    <string name="bottom_action_people">Persoanen</string>
     <string name="bottom_action_rooms">Petearen</string>
     <string name="bottom_action_groups">Mienskippen</string>
     <string name="home_filter_placeholder_home">Petearnammen filterje</string>
@@ -138,40 +138,41 @@
     <string name="send_bug_report_placeholder">Beskriuw hjir jo probleem</string>
     <string name="finish">Ôfrûnje</string>
     <string name="keep_it_safe">Hâld it feilich</string>
-    <string name="bootstrap_finish_title">Do binst klear!</string>
-    <string name="bootstrap_save_key_description">Brûk disse %1$s as in feiligensnet, foar it gefal ast dyn %2$s ferjitst.</string>
+    <string name="bootstrap_finish_title">Klear!</string>
+    <string name="bootstrap_save_key_description">Brûk dizze %1$s as in befeiligingsnet, foar it gefal as jo %2$s ferjitte.</string>
     <string name="call_notification_hangup">Ophingje</string>
-    <string name="call_notification_reject">Ferfalle litte</string>
+    <string name="call_notification_reject">Ofwize</string>
     <string name="call_notification_answer">Akseptearje</string>
-    <string name="notice_room_canonical_alias_unset_by_you">Do hast it haadadres fan dizze keamer fuortsmiten.</string>
-    <string name="notice_room_canonical_alias_no_change">%1$s hat it adres fan dizze keamer feroare.</string>
-    <string name="notice_room_canonical_alias_no_change_by_you">Do hast it adres fan dizze keamer feroare.</string>
-    <string name="notice_direct_room_leave_with_reason_by_you">Do binst fuort gien. Reden: %1$s</string>
+    <string name="notice_room_canonical_alias_unset_by_you">Jo hawwe it haadadres fan dit petear fuortsmiten.</string>
+    <string name="notice_room_canonical_alias_no_change">%1$s hat it petearadres wizige.</string>
+    <string name="notice_room_canonical_alias_no_change_by_you">Jo hawwe it petearadres wizige.</string>
+    <string name="notice_direct_room_leave_with_reason_by_you">Jo binne fuortgien. Reden: %1$s</string>
     <string name="notice_direct_room_leave_with_reason">%1$s is fuort gien. Reden: %2$s</string>
-    <string name="notice_room_leave_with_reason_by_you">Do hast de keamer ferlitten. Reden: %1$s</string>
+    <string name="notice_room_leave_with_reason_by_you">Jo hawwe de keamer ferlitten. Reden: %1$s</string>
     <string name="notice_room_leave_with_reason">%1$s hat de keamer ferlitten. Reden: %2$s</string>
-    <string name="notice_direct_room_join_with_reason_by_you">Do binst de keamer yn kaam. Reden: %1$s</string>
+    <string name="notice_direct_room_join_with_reason_by_you">Jo binne de keamer yn kaam. Reden: %1$s</string>
     <string name="notice_direct_room_join_with_reason">%1$s is de keamer yn kaam. Reden: %2$s</string>
-    <string name="notice_room_join_with_reason_by_you">Do binst de keamer yn kaam. Reden: %1$s</string>
+    <string name="notice_room_join_with_reason_by_you">Jo binne de keamer yn kaam. Reden: %1$s</string>
     <string name="notice_room_join_with_reason">%1$s is de keamer yn kaam. Reden: %2$s</string>
-    <string name="notice_room_invite_you_with_reason">%1$s hat dy útnûge. Reden: %2$s</string>
-    <string name="notice_room_invite_with_reason_by_you">Do hast %1$s útnûge. Reden: %2$s</string>
+    <string name="notice_room_invite_you_with_reason">%1$s hat jo útnûge. Reden: %2$s</string>
+    <string name="notice_room_invite_with_reason_by_you">Jo hawwe %1$s útnûge. Reden: %2$s</string>
     <string name="notice_room_invite_with_reason">%1$s hat %2$s útnûge. Reden: %3$s</string>
-    <string name="notice_room_invite_no_invitee_with_reason_by_you">Dyn útnûging. Reden: %1$s</string>
+    <string name="notice_room_invite_no_invitee_with_reason_by_you">Jo útnûging. Reden: %1$s</string>
     <string name="notice_room_invite_no_invitee_with_reason">%1$s harren útnûging. Reden: %2$s</string>
-    <string name="clear_timeline_send_queue">Ferstjoeringslist leech meitsje</string>
+    <string name="clear_timeline_send_queue">Utgeande wachtrige wiskje</string>
     <string name="event_status_sending_message">Berjocht oan it fersjoeren…</string>
     <string name="event_status_sent_message">Berjocht ferstjoerd</string>
-    <string name="initial_sync_start_importing_account_data">Inisjele Syngronisaasje:
-\nAkkount Data Binnenhelje</string>
+    <string name="initial_sync_start_importing_account_data">Inisjele syngronisaasje:
+\nAccountgegevens ymportearje</string>
     <string name="initial_sync_start_importing_account_groups">Inisjele Syngronisaasje:
-\nMienskippen Binnenhelje</string>
+\nMienskippen ymportearje</string>
     <string name="initial_sync_start_importing_account_left_rooms">Inisjele Syngronisaasje:
-\nOerblieuwne Keamers Binnenhelje</string>
+\nFerlitten keamers ymportearje</string>
     <string name="initial_sync_start_importing_account_invited_rooms">Inisjele syngronisaasje:
-\nKeamers dêr\'t jo foar útnûge binne ymportearje</string>
+\nKeamers dêr’t jo foar útnûge binne ymportearje</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Inisjele syngronisaasje:
-\nKeamers wer ast yn kaam bist ymportearje</string>
+\nJo petearen lade
+\nAs jo yn in protte keamers binne kin dit efkes duorje</string>
     <string name="initial_sync_start_importing_account_rooms">Inisjele syngronisaasje:
 \nKeamers ymportearje</string>
     <string name="initial_sync_start_importing_account">Inisjele syngronisaasje:
@@ -181,49 +182,49 @@
     <string name="initial_sync_start_server_computing">Inisjele syngronisaasje:
 \nWachtsjend op reaksje fan server…</string>
     <string name="room_displayname_empty_room_was">Lege keamer (wie %s)</string>
-    <string name="room_displayname_empty_room">Lege keamer</string>
+    <string name="room_displayname_empty_room">Leech petear</string>
     <string name="medium_email">E-mailadres</string>
     <string name="room_displayname_invite_from">Utnûging fan %s</string>
     <string name="medium_phone_number">Telefoannûmer</string>
     <string name="message_failed_to_upload">Opladen fan ôfbylding mislearre</string>
-    <string name="notice_crypto_unable_to_decrypt">** Koe %s net ûntsiferje **</string>
+    <string name="notice_crypto_unable_to_decrypt">** Koe net ûntsiferje: %s **</string>
     <string name="could_not_redact">Koe net ynlûke</string>
     <string name="power_level_custom_no_value">Oanpast</string>
     <string name="power_level_custom">Oanpast (%1$d)</string>
     <string name="power_level_default">Standert</string>
-    <string name="notice_widget_jitsi_modified_by_you">Do hast de fideokonferinsje oanpast</string>
+    <string name="notice_widget_jitsi_modified_by_you">Jo hawwe de fideokonferinsje oanpast</string>
     <string name="power_level_admin">Behearder</string>
     <string name="notice_event_redacted_by_with_reason">Berjocht fuortsmiten troch %1$s [reden: %2$s]</string>
     <string name="notice_event_redacted_with_reason">Berjocht fuortsmiten [reden: %1$s]</string>
     <string name="notice_event_redacted_by">Berjocht fuortsmiten troch %1$s</string>
-    <string name="notice_room_server_acl_updated_no_change">Gjin feroaringen.</string>
-    <string name="notice_room_server_acl_set_allowed">• Tsjinners dy foldoche oan %s bin tastien.</string>
-    <string name="notice_room_server_acl_set_title_by_you">Do hast de ACLs foar de keamer opnij ynsteld.</string>
-    <string name="notice_room_server_acl_set_title">%s hat de ACLs foar disse keamer ynsteld.</string>
-    <string name="notice_room_update_by_you">Do hast disse keamer opwurdeare.</string>
-    <string name="notice_room_update">%s hat disse keamer upwurdeare.</string>
-    <string name="notice_end_to_end_by_you">Do hast end-to-end fersifering ynskakele (%1$s)</string>
-    <string name="notice_end_to_end">%1$s hat end-to-end fersifering ynskakele (%2$s)</string>
+    <string name="notice_room_server_acl_updated_no_change">Gjin wizigingen.</string>
+    <string name="notice_room_server_acl_set_allowed">• Servers dy’t oerienkomme mei %s binne tastien.</string>
+    <string name="notice_room_server_acl_set_title_by_you">Jo hawwe de ACL’s foar dizze keamer ynsteld.</string>
+    <string name="notice_room_server_acl_set_title">%s hat de ACL’s foar dizze keamer ynsteld.</string>
+    <string name="notice_room_update_by_you">Jo hawwe dizze keamer opwurdearre.</string>
+    <string name="notice_room_update">%s hat dizze keamer opwurdearre.</string>
+    <string name="notice_end_to_end_by_you">Jo hawwe end-to-end-fersifering ynskeakele (%1$s)</string>
+    <string name="notice_end_to_end">%1$s hat end-to-end-fersifering ynskeakele (%2$s)</string>
     <string name="notice_room_visibility_unknown">ûnbekend (%s).</string>
-    <string name="notice_room_visibility_shared">Alle keamerleden.</string>
-    <string name="notice_room_visibility_joined">Olle keamerleden, fanôf it momint dot se de keamer ynkaam binne.</string>
-    <string name="notice_room_visibility_invited">Olle keamerleden, fanôf it momint dot se útnûge binne.</string>
+    <string name="notice_room_visibility_shared">alle dielnimmers oan it petear.</string>
+    <string name="notice_room_visibility_joined">alle dielnimmers, fan it momint ôf dat se de keamer ynkaam binne.</string>
+    <string name="notice_room_visibility_invited">alle dielnimmers oan it petear, fan it momint ôf dat se útnûge binne.</string>
     <string name="summary_message">%1$s: %2$s</string>
     <string name="space_type_public_desc">Iepen foar eltsenien, it beste foar mienskippen</string>
     <string name="group_all_communities">Alle mienskippen</string>
     <string name="community_id">Mienskips ID</string>
     <string name="community_name">Mienskipsnamme</string>
     <string name="create_community">Mienskip Oanmeitsje</string>
-    <string name="room_settings_invalid_group_format_dialog_body">\'%s\' is net in jildich mienskips ID</string>
+    <string name="room_settings_invalid_group_format_dialog_body">‘%s’ is net in jildich mienskips-ID</string>
     <string name="room_settings_invalid_group_format_dialog_title">Ûnjildich mienskips ID</string>
     <string name="room_settings_add_new_group">Nije mienskips ID (b.v. +foo:matrix.org)</string>
-    <string name="settings_without_flair">Do binst op it momint net lid fan in mienskip.</string>
+    <string name="settings_without_flair">Jo binne op dit stuit net lid fan in mienskip.</string>
     <string name="dialog_title_success">Sukses</string>
-    <string name="room_participants_invite_search_another_user">Brûkers ID, Namme of email</string>
-    <string name="room_participants_action_leave">Disse keamer ferlitte</string>
+    <string name="room_participants_invite_search_another_user">Brûkers-ID, namme of e-mailadres</string>
+    <string name="room_participants_action_leave">Dizze keamer ferlitte</string>
     <string name="room_participants_create">Oanmeitsje</string>
-    <string name="room_participants_action_remove">Út disse keamer smite</string>
-    <string name="room_settings_enable_encryption_no_permission">Do hast gjin tastimming om enkripsje yn te skakeljen yn disse keamer.</string>
+    <string name="room_participants_action_remove">Ut dizze keamer fuortsmite</string>
+    <string name="room_settings_enable_encryption_no_permission">Jo hawwe gjin tastimming om fersifering yn dizze keamer yn te skeakeljen.</string>
     <string name="sound_device_phone">Telefoan</string>
     <string name="call_failed_dont_ask_again">My net wer freegje</string>
     <string name="start_new_chat">Nij petear begjinne</string>
@@ -236,32 +237,32 @@
     <string name="search_in_my_contacts">Yn mien kontakten sykje</string>
     <string name="phone_book_perform_lookup">Om matrix kontakten sykje</string>
     <string name="message_action_item_redact">Fuortsmite…</string>
-    <string name="share_confirm_room">Wolst dit taheaksel fersjoere nei %1$s\?</string>
+    <string name="share_confirm_room">Wolle jo dizze bylage nei %1$s ferstjoere\?</string>
     <string name="send_attachment">Taheaksel ferstjoere</string>
     <string name="settings_text_message_sent_wrong_code">De ferifikaasje koade is net jildich.</string>
     <string name="settings_text_message_sent_hint">Koade</string>
-    <string name="settings_text_message_sent">In tekst berjocht is nei %s stjoerd. Graach de ferifikaasje koade ynfiere dyt der yn stiet.</string>
-    <string name="settings_discovery_bad_identity_server">Kin net ferbine mei identiteits tsjinner</string>
-    <string name="settings_discovery_enter_identity_server">Identiteits tsjinner URL ynfiere</string>
-    <string name="identity_server_consent_dialog_title">Emails en tillefoan nûmers ferstjoere</string>
+    <string name="settings_text_message_sent">In tekstberjocht is nei %s stjoerd. Graach de ferifikaasjekoade ynfiere dy’t der ynstiet.</string>
+    <string name="settings_discovery_bad_identity_server">Kin net ferbine mei identiteitsserver</string>
+    <string name="settings_discovery_enter_identity_server">Fier identiteitsserver-URL yn</string>
+    <string name="identity_server_consent_dialog_title">E-mailadressen en telefoannûmers ferstjoere</string>
     <string name="settings_discovery_consent_action_give_consent">Tastimming jaan</string>
     <string name="settings_discovery_consent_action_revoke">Tastimming wer ynlûke</string>
-    <string name="settings_discovery_consent_notice_off">Do hast gjin tastimming jûn emails en tillefoan nûmers nei disse identiteits tsjinner te stjoeren, om oare brûkers út dyn kontakten te finen.</string>
-    <string name="settings_discovery_consent_notice_on">Do hast tastimming jûn emails en tillefoan nûmers nei disse identiteits tsjinner te stjoeren, om oare brûkers út dyn kontakten te finen.</string>
-    <string name="settings_discovery_consent_title">Emails en tillefoan nûmers ferstjoere</string>
+    <string name="settings_discovery_consent_notice_off">Om oare brûkers út jo kontakten te finen, hawwe jo gjin tastimming jûn e-mailadressen en telefoannûmers nei dizze identiteitsserver te stjoeren.</string>
+    <string name="settings_discovery_consent_notice_on">Om oare brûkers út jo kontakten te finen, hawwe jo tastimming jûn e-mailadressen en telefoannûmers nei dizze identiteitsserver te stjoeren.</string>
+    <string name="settings_discovery_consent_title">E-mailadressen en telefoannûmers ferstjoere</string>
     <string name="settings_discovery_mail_pending">Yn ôfwachting</string>
     <string name="terms_description_for_integration_manager">Bots, brêgen, widgets en sticker paketten brûke</string>
     <string name="terms_description_for_identity_server">Foar oaren fynber wéze</string>
-    <string name="message_view_edit_history">Feroarings Skiednis Besjen</string>
+    <string name="message_view_edit_history">Bewurkingsskiednis toane</string>
     <string name="joining_room">Keamer binnen gean…</string>
     <string name="creating_direct_room">Keamer wurd oanmakke…</string>
     <string name="room_filtering_footer_create_new_room">Nije keamer oanmeitsje</string>
     <string name="no_message_edits_found">Gjin feroaringen fûn</string>
-    <string name="edited_suffix">(feroare)</string>
+    <string name="edited_suffix">(bewurke)</string>
     <string name="send_file_step_idle">Wachtsjend…</string>
     <string name="preference_root_help_about">Hulp &amp; Oer</string>
     <string name="quick_reactions">Flugge Reaksjes</string>
-    <string name="settings_sdk_version">Matrix SDK Ferzje</string>
+    <string name="settings_sdk_version">Matrix SDK-ferzje</string>
     <string name="create_room_settings_section">Keamer ynstellings</string>
     <string name="create_room_topic_hint">Ûnderwerp</string>
     <string name="create_room_topic_section">Keamer ûnderwerp (opsjoneel)</string>
@@ -271,53 +272,53 @@
     <string name="create_room_title">Nije Keamer</string>
     <string name="fab_menu_create_chat">Direkte Berjochten</string>
     <string name="fab_menu_create_room">Keamers</string>
-    <string name="room_preview_no_preview_join">Disse keamer kin net ynsjûn wurde. Wolst de keamer binnen gean\?</string>
-    <string name="room_preview_not_found">Disse keamer jout no gjin tagong.
-\nProbearje it letter noch ris in kear, of freechje in administrator om te sjen ast wol de nediche rjochten hast.</string>
+    <string name="room_preview_no_preview_join">Dizze keamer kin net yn it foar toand wurde. Wolle jo de keamer binnen gean\?</string>
+    <string name="room_preview_not_found">Dizze keamer jout no gjin tagong.
+\nProbearje it letter noch ris, of freegje in behearder om te sjen oft jo wol de nedige rjochten hawwe.</string>
     <string name="template_room_preview_world_readable_room_not_supported_yet">Ynsjoch yn wrâld-lésbere keamers wurd noch net stipe troch ${app_name}</string>
-    <string name="room_preview_no_preview">Disse keamer kin net ynsjûn wurde</string>
+    <string name="room_preview_no_preview">Dizze keamer kin net yn it foar toand wurde</string>
     <string name="please_wait">Graach efkes wachtsje…</string>
     <string name="change_room_directory_network">Netwurk feroarje</string>
     <string name="action_change">Feroarje</string>
-    <string name="error_no_network">Gjin netwurk. Kontroleerje dyn internet ferbyning.</string>
+    <string name="error_no_network">Gjin netwurk. Kontrolearje jo ynternetferbining.</string>
     <string name="create_new_room">Nije Keamer Meitsje</string>
-    <string name="malformed_message">Net gûd foarme evenemint, kin net sjen litten wurde</string>
-    <string name="last_edited_info_message">Foar it letst feroare troch %1$s op %2$s</string>
+    <string name="malformed_message">Net krekt foarme evenemint, kin net toand wurde</string>
+    <string name="last_edited_info_message">Foar it lêst troch %1$s wizige op %2$s</string>
     <string name="event_redacted_by_user_reason">Evenemint troch brûker fuortsmiten</string>
-    <string name="settings_show_redacted">Fuortsmiten berjiochten sjen litte</string>
+    <string name="settings_show_redacted">Fuortsmiten berjochten toane</string>
     <string name="event_redacted">Berjocht fuortsmiten</string>
     <string name="reactions">Reaksjes</string>
     <string name="create_room_directory_title">Keamer List</string>
-    <string name="create_room_public_description">Eltsenien kin disse keamer binnen gean</string>
+    <string name="create_room_public_description">Elkenien kin dizze keamer binnen gean</string>
     <string name="create_room_public_title">Iepenbier</string>
     <string name="settings_preferences">Foarkarren</string>
     <string name="send_suggestion">Sugestje dwaan</string>
     <string name="room_preview_try_join_an_unknown_room_default">in keamer</string>
-    <string name="room_creation_title">Nij Petear</string>
+    <string name="room_creation_title">Nije chat</string>
     <string name="preview">Ynsjen</string>
     <string name="join">Meidwaan</string>
     <string name="remove">Fuortsmite</string>
-    <string name="_continue">Troch gean</string>
+    <string name="_continue">Trochgean</string>
     <string name="no">NEE</string>
     <string name="yes">JA</string>
-    <string name="permissions_rationale_popup_title">Informaasje</string>
-    <string name="call_resume_action">Troch gean</string>
-    <string name="room_info_room_topic">Keamer ûnderwerp</string>
-    <string name="room_info_room_name">Keamer namme</string>
-    <string name="today">Hjoerd</string>
+    <string name="permissions_rationale_popup_title">Ynformaasje</string>
+    <string name="call_resume_action">Trochgean</string>
+    <string name="room_info_room_topic">Keamerûnderwerp</string>
+    <string name="room_info_room_name">Keamernamme</string>
+    <string name="today">Hjoed</string>
     <string name="yesterday">Juster</string>
     <string name="compression_opt_list_small">Lyts</string>
     <string name="compression_opt_list_medium">Gemiddeld</string>
     <string name="compression_opt_list_large">Grut</string>
-    <string name="compression_opt_list_original">Orizineel</string>
-    <string name="compression_options">Ferstjoer as</string>
+    <string name="compression_opt_list_original">Orizjineel</string>
+    <string name="compression_options">Ferstjoere as</string>
     <plurals name="membership_changes">
-        <item quantity="one">%d lidmaatskip wiizige</item>
-        <item quantity="other">%d lidmaatskippen wiizige</item>
+        <item quantity="one">%d lidmaatskip wizige</item>
+        <item quantity="other">%d lidmaatskippen wizige</item>
     </plurals>
     <string name="groups_list">Groepslist</string>
     <string name="e2e_re_request_encryption_key_dialog_title">Oanfraach ferstjoerd</string>
-    <string name="e2e_re_request_encryption_key_sent">Kaai oanfraach ferstjoerd.</string>
+    <string name="e2e_re_request_encryption_key_sent">Kaaioanfraach ferstjoerd.</string>
     <string name="login_error_login_email_not_yet">Der is noch net op de keppeling yn it e-mailberjocht klikt</string>
     <string name="login_error_user_in_use">Dizze brûkersnamme is al yn gebrûk</string>
     <string name="login_error_limit_exceeded">Der binne te folle oanfragen ferstjoerd</string>
@@ -328,19 +329,19 @@
     <string name="login_error_homeserver_not_found">Kin de thússerver op dizze URL net berikke, kontrolearje dit</string>
     <string name="login_error_no_homeserver_found">Dit is net in jildich Matrix-serveradres</string>
     <string name="login_error_unknown_host">Dizze URL is net te berikken, kontrolearje dit</string>
-    <string name="login_error_invalid_home_server">Fier in jildiche URL yn</string>
+    <string name="login_error_invalid_home_server">Fier in jildige URL yn</string>
     <string name="login_error_unable_register">Registrearjen mislearre</string>
     <string name="login_error_registration_network_error">Kin net registrearje: netwurkflater</string>
-    <string name="login_error_unable_login">Kin net oanmelde</string>
+    <string name="login_error_unable_login">Oanmelden mislearre</string>
     <string name="auth_reset_password_error_unauthorized">Koe it e-mailadres net ferifiearje: soargje dat jo op de keppeling yn it e-mailberjocht klikt hawwe</string>
-    <string name="auth_reset_password_email_validation_message">Der is in e-mail nei %s stjoerd. Klik hjirûnder sa gau as jo de keppeling yn de e-mail besocht hawwe.</string>
-    <string name="auth_email_validation_message">Kontrolearje dyn e-mail om troch te gean mei de registraasje</string>
+    <string name="auth_reset_password_email_validation_message">Der is in e-mailberjocht stjoerd nei %s. Klik hjirûnder sa gau as jo de keppeling yn it e-mailberjocht besocht hawwe.</string>
+    <string name="auth_email_validation_message">Kontrolearje jo e-mail om troch te gean mei de registraasje</string>
     <string name="auth_forgot_password">Wachtwurd fergetten\?</string>
-    <string name="auth_password_dont_match">Wachtwurden binne net gelyk</string>
+    <string name="auth_password_dont_match">Wachtwurden binne net lyk</string>
     <string name="auth_invalid_token">Unjildich token</string>
-    <string name="auth_missing_email_or_phone">Der mist in e-mailadres of telefoannûmer</string>
-    <string name="auth_missing_phone">Telefoannûmer mist</string>
-    <string name="auth_missing_email">E-mailadres mist</string>
+    <string name="auth_missing_email_or_phone">E-mailadres of telefoannûmer ûntbrekt</string>
+    <string name="auth_missing_phone">Telefoannûmer ûntbrekt</string>
+    <string name="auth_missing_email">E-mailadres ûntbrekt</string>
     <string name="auth_email_already_defined">Dit e-mailadres is al yn gebrûk.</string>
     <string name="auth_invalid_phone">Dit is gjin jildich telefoannûmer</string>
     <string name="auth_opt_phone_number_placeholder">Telefoannûmer (opsjoneel)</string>
@@ -353,7 +354,7 @@
     <string name="option_take_video">Fideo meitsje</string>
     <string name="option_take_photo">Foto meitsje</string>
     <string name="option_take_photo_video">Foto of fideo meitsje</string>
-    <string name="option_send_sticker">Stickers ferstjoere</string>
+    <string name="option_send_sticker">Stikkers ferstjoere</string>
     <string name="option_send_files">Bestannen ferstjoere</string>
     <string name="call_format_turn_hd_on">HD ynskeakelje</string>
     <string name="call_format_turn_hd_off">HD útskeakelje</string>
@@ -370,13 +371,13 @@
     <string name="auth_identity_server">Identiteitsserver:</string>
     <string name="auth_home_server">Thússerver:</string>
     <string name="auth_username_in_use">Brûkersnamme al yn gebrûk</string>
-    <string name="settings_security_and_privacy">Feiligens &amp; Privacy</string>
+    <string name="settings_security_and_privacy">Befeiliging &amp; privacy</string>
     <string name="room_widget_resource_grant_permission">Tastean</string>
-    <string name="room_settings_room_version_title">Keamer ferzje</string>
-    <string name="room_settings_category_advanced_title">Avanseare</string>
-    <string name="room_settings_room_access_restricted_title">Rômtes</string>
+    <string name="room_settings_room_version_title">Keamerferzje</string>
+    <string name="room_settings_category_advanced_title">Avansearre</string>
+    <string name="room_settings_room_access_restricted_title">Romten allinnich leden</string>
     <string name="room_settings_room_access_public_description">Eltsenien kin de keamer fyne en der yn komme</string>
-    <string name="room_settings_read_history_entry_anyone">Eltsenien</string>
+    <string name="room_settings_read_history_entry_anyone">Elkenien</string>
     <string name="room_settings_guest_access_title">Gasten tastean om de keamer yn te gean</string>
     <string name="room_alias_published_alias_main">Dit is it haad adres</string>
     <string name="room_alias_main_address_hint">Haad adres</string>
@@ -384,71 +385,71 @@
     <string name="media_saving_period_1_month">1 moanne</string>
     <string name="media_saving_period_1_week">1 wike</string>
     <string name="media_saving_period_3_days">3 dagen</string>
-    <string name="media_saving_period_forever">Foar oltiid</string>
+    <string name="media_saving_period_forever">Altyd</string>
     <string name="action_add">Tafoegje</string>
     <string name="bottom_action_notification">Notifikaasjes</string>
-    <string name="create_spaces_default_public_room_name">Olgemien</string>
+    <string name="create_spaces_default_public_room_name">Algemien</string>
     <string name="matrix_error">Matrix-flater</string>
     <string name="network_error">Netwurkflater</string>
     <string name="unable_to_send_message">Kin it berjocht net ferstjoere</string>
     <string name="notice_event_redacted">Berjocht fuortsmiten</string>
-    <string name="labs_use_restricted_join_rule_desc">Waskôging hat ûndersteuning fan\'e tsjinner en in eksperimintele keamer nedich</string>
+    <string name="labs_use_restricted_join_rule_desc">Warskôging hat serverstipe en in eksperimintele keamer nedich</string>
     <string name="labs_use_restricted_join_rule">Eksperiminteel Rômte - Beheinde Keamer.</string>
-    <string name="you_are_invited">Do bist útnûge</string>
-    <string name="notice_room_visibility_world_readable">eltsenien.</string>
-    <string name="notice_made_future_direct_room_visibility_by_you">Do hast takomstige berjochten foar %1$s sichtber makke</string>
+    <string name="you_are_invited">Jo binne útnûge</string>
+    <string name="notice_room_visibility_world_readable">elkenien.</string>
+    <string name="notice_made_future_direct_room_visibility_by_you">Jo hawwe takomstige berjochten foar %1$s sichtber makke</string>
     <string name="notice_made_future_direct_room_visibility">%1$s hat takomstige berjochten foar %2$s sichtber makke</string>
-    <string name="notice_made_future_room_visibility_by_you">Do hast de takomstige keamer skiednis foar %1$s sichtber makke</string>
-    <string name="notice_made_future_room_visibility">%1$s hat de takomstige keamer skiednis foar %2$s sichtber makke</string>
-    <string name="notice_ended_call_by_you">Do hast it petear beënige.</string>
+    <string name="notice_made_future_room_visibility_by_you">Jo hawwe de takomstige petearskiednis foar %1$s sichtber makke</string>
+    <string name="notice_made_future_room_visibility">%1$s hat de takomstige petearskiednis foar %2$s sichtber makke</string>
+    <string name="notice_ended_call_by_you">Jo hawwe de oprop beëinige.</string>
     <string name="notice_ended_call">%s hat it petear beëinige.</string>
-    <string name="notice_answered_call_by_you">Do hast it petear beantwurde.</string>
-    <string name="notice_answered_call">%s hat it petear beantwurde.</string>
-    <string name="notice_call_candidates_by_you">Do hast data stjoerd om in petear op te setten.</string>
+    <string name="notice_answered_call_by_you">Jo hawwe de oprop beäntwurde.</string>
+    <string name="notice_answered_call">%s hat de oprop beäntwurde.</string>
+    <string name="notice_call_candidates_by_you">Jo hawwe data stjoerd om in petear op te setten.</string>
     <string name="notice_call_candidates">%s hat data stjoerd om in petear op te setten.</string>
-    <string name="notice_placed_voice_call">%s hat in fideo petear oanmakke.</string>
-    <string name="notice_placed_video_call_by_you">Do hast in fideo petear oanmakke.</string>
-    <string name="notice_placed_video_call">%s hat in fideo petear oanmakke.</string>
-    <string name="notice_room_name_changed_by_you">Do hast de namme fan\'e keamer feroare nei: %1$s</string>
-    <string name="notice_room_name_changed">%1$s hat de namme fan\'e keamer feroare nei: %2$s</string>
-    <string name="notice_room_topic_changed_by_you">Do hast it ûnderwerp feroare nei: %1$s</string>
-    <string name="notice_room_topic_changed">%1$s hat it ûnderwerp feroare nei: %2$s</string>
-    <string name="notice_display_name_removed_by_you">Do hast dyn namme fuortsmiten (it wie %1$s)</string>
-    <string name="notice_display_name_removed">%1$s hat syn namme fuortsmiten (it wie %2$s)</string>
-    <string name="notice_display_name_changed_from_by_you">Do hast dyn namme fan %1$s nei %2$s feroare</string>
-    <string name="notice_display_name_changed_from">%1$s hat syn namme fan %2$s nei %3$s feroare</string>
-    <string name="notice_display_name_set_by_you">Do hast dyn namme nei %1$s feroare</string>
-    <string name="notice_display_name_set">%1$s hat syn namme nei %2$s feroare</string>
-    <string name="notice_room_withdraw_by_you">Do hast de útnûging foar %1$s wer ynlutsen</string>
+    <string name="notice_placed_voice_call">%s hat in fideopetear oanmakke.</string>
+    <string name="notice_placed_video_call_by_you">Jo hawwe in fideopetear iepene.</string>
+    <string name="notice_placed_video_call">%s hat in fideo-oprop oanmakke.</string>
+    <string name="notice_room_name_changed_by_you">Jo hawwe de keamernamme wizige nei: %1$s</string>
+    <string name="notice_room_name_changed">%1$s hat de petearnamme wizige nei: %2$s</string>
+    <string name="notice_room_topic_changed_by_you">Jo hawwe it ûnderwerp wizige nei: %1$s</string>
+    <string name="notice_room_topic_changed">%1$s hat it ûnderwerp wizige nei: %2$s</string>
+    <string name="notice_display_name_removed_by_you">Jo hawwe jo werjeftenamme fuortsmiten (wie %1$s)</string>
+    <string name="notice_display_name_removed">%1$s hat de werjeftenamme fuortsmiten (wie %2$s)</string>
+    <string name="notice_display_name_changed_from_by_you">Jo hawwe jo werjeftenamme fan %1$s wizige nei %2$s</string>
+    <string name="notice_display_name_changed_from">%1$s hat de werjeftenamme fan %2$s wizige nei %3$s</string>
+    <string name="notice_display_name_set_by_you">Jo hawwe jo werjeftenamme wizige nei %1$s</string>
+    <string name="notice_display_name_set">%1$s hat de werjeftenamme wizige nei %2$s</string>
+    <string name="notice_room_withdraw_by_you">Jo hawwe de útnûging foar %1$s wer ynlutsen</string>
     <string name="notice_room_withdraw">%1$s hat de útnûging foar %2$s wer ynlutsen</string>
-    <string name="notice_room_ban_by_you">Do hast %1$s ferbonne</string>
-    <string name="notice_direct_room_join_by_you">Do bist de keamer yn kaam</string>
-    <string name="notice_room_ban">%1$s hat %2$s ferbonne</string>
-    <string name="notice_room_kick_by_you">Do hast %1$s der út skopt</string>
-    <string name="notice_room_kick">%1$s hat %2$s der út skopt</string>
-    <string name="notice_room_reject_by_you">Do hast de útnûging ôfwiisd</string>
-    <string name="notice_room_reject">%1$s hat de útnûging ôfwiisd</string>
-    <string name="notice_direct_room_leave_by_you">Do hast de keamer ferlitten</string>
+    <string name="notice_room_ban_by_you">Jo hawwe %1$s ferballe</string>
+    <string name="notice_direct_room_join_by_you">Jo binne oansluten</string>
+    <string name="notice_room_ban">%1$s hat %2$s ferballe</string>
+    <string name="notice_room_kick_by_you">Jo hawwe %1$s der útskopt</string>
+    <string name="notice_room_kick">%1$s hat %2$s der útskopt</string>
+    <string name="notice_room_reject_by_you">Jo hawwe de útnûging wegere</string>
+    <string name="notice_room_reject">%1$s hat de útnûging wegere</string>
+    <string name="notice_direct_room_leave_by_you">Jo hawwe de keamer ferlitten</string>
     <string name="notice_direct_room_leave">%1$s hat de keamer ferlitten</string>
-    <string name="notice_room_leave_by_you">Do hast de keamer ferlitten</string>
+    <string name="notice_room_leave_by_you">Jo hawwe de keamer ferlitten</string>
     <string name="notice_room_leave">%1$s hat de keamer ferlitten</string>
     <string name="notice_direct_room_join">%1$s is de keamer yn kaam</string>
-    <string name="notice_room_join_by_you">Do bist de keamer yn kaam</string>
-    <string name="notice_room_join">%1$s is de keamer yn kaam</string>
-    <string name="notice_room_invite_you">%1$s hat dy útnûge</string>
-    <string name="notice_room_invite_by_you">Do hast %1$s útnûge</string>
+    <string name="notice_room_join_by_you">Jo binne de keamer yn kaam</string>
+    <string name="notice_room_join">%1$s nimt no diel oan it petear</string>
+    <string name="notice_room_invite_you">%1$s hat jo útnûge</string>
+    <string name="notice_room_invite_by_you">Jo hawwe %1$s útnûge</string>
     <string name="notice_room_invite">%1$s hat %2$s útnûge</string>
-    <string name="notice_direct_room_created_by_you">Do hast de diskusje oanmakke</string>
+    <string name="notice_direct_room_created_by_you">Jo hawwe de diskusje oanmakke</string>
     <string name="notice_direct_room_created">%1$s hat de diskusje oanmakke</string>
-    <string name="notice_room_created_by_you">Do hast de keamer oanmakke</string>
+    <string name="notice_room_created_by_you">Jo hawwe de keamer oanmakke</string>
     <string name="notice_room_created">%1$s hat de keamer oanmakke</string>
-    <string name="notice_room_invite_no_invitee_by_you">Dyn útnûging</string>
-    <string name="notice_room_invite_no_invitee">%s\'s útnûging</string>
-    <string name="summary_you_sent_sticker">Do hast in sticker stjoerd.</string>
-    <string name="summary_user_sent_sticker">%1$s hat in sticker stjoerd.</string>
-    <string name="summary_you_sent_image">Do hast in ôfbylding stjoerd.</string>
+    <string name="notice_room_invite_no_invitee_by_you">Jo útnûging</string>
+    <string name="notice_room_invite_no_invitee">Utnûging fan %s</string>
+    <string name="summary_you_sent_sticker">Jo hawwe in stikker stjoerd.</string>
+    <string name="summary_user_sent_sticker">%1$s hat in stikker stjoerd.</string>
+    <string name="summary_you_sent_image">Jo hawwe in ôfbylding stjoerd.</string>
     <string name="summary_user_sent_image">%1$s hat in ôfbylding stjoerd.</string>
-    <string name="no_valid_google_play_services_apk">Gjin jildiche Google Play Services APK fûn. Notifikaasjes kinne wol ris net wurkje.</string>
+    <string name="no_valid_google_play_services_apk">Gjin jildige Google Play Services APK fûn. Notifikaasjes kinne wolris net wurkje.</string>
     <string name="x_plus">%d+</string>
     <string name="plus_x">+%d</string>
     <string name="generic_label_and_value">%1$s: %2$s</string>
@@ -456,54 +457,54 @@
     <string name="show_info_area_only_errors">Allinich foar flaters</string>
     <string name="show_info_area_messages_and_errors">Foar berjochten en flaters</string>
     <string name="show_info_area_always">Ivich</string>
-    <string name="settings_info_area_show">Informaasje krite sjen litte</string>
+    <string name="settings_info_area_show">Ynformaasjegebiet toane</string>
     <string name="merged_events_collapse">ynteare</string>
     <string name="merged_events_expand">útteare</string>
     <string name="unknown_error">Sorry, in flater die sich foar</string>
-    <string name="resource_limit_hard_contact">Graach %s om disse tsjinst brûken te blieuwen.</string>
+    <string name="resource_limit_hard_contact">Graach %s om dizze tsjinst brûke te bliuwen.</string>
     <string name="room_tombstone_predecessor_link">Klik hjir om âldere berjochten te besjen</string>
-    <string name="room_tombstone_continuation_description">Disse keamer is in trochsetting fan in oar petear</string>
+    <string name="room_tombstone_continuation_description">Dizze keamer is in fuortsetting fan in oar petear</string>
     <string name="room_tombstone_continuation_link">It petear giet hjir troch</string>
-    <string name="room_tombstone_versioned_description">Disse keamer is ferfong en is net mear aktyf.</string>
-    <string name="error_empty_field_your_password">Graach dyn wachtwurd ynfiere.</string>
-    <string name="error_empty_field_enter_user_name">Graach in brûkersnamme ynfiere.</string>
-    <string name="deactivate_account_submit">Akkount Útskeakelje</string>
-    <string name="deactivate_account_prompt_password">Om troch te gean, fier dyn wachtwurd yn:</string>
-    <string name="deactivate_account_delete_checkbox">Graach alle berjochten ferjitte dyt ik ferstjoerd ha wannear myn akkount útskeakele is (Warskôging: hjir troch kin oare brûkers in ûnfolslein byld fan konversaasjes krijge)</string>
-    <string name="deactivate_account_title">Akkount Deaktivearje</string>
+    <string name="room_tombstone_versioned_description">Dizze keamer is ferfongen en is net mear aktyf.</string>
+    <string name="error_empty_field_your_password">Fier jo wachtwurd yn.</string>
+    <string name="error_empty_field_enter_user_name">Fier in brûkersnamme yn.</string>
+    <string name="deactivate_account_submit">Account útskeakelje</string>
+    <string name="deactivate_account_prompt_password">Om troch te gean, fier jo wachtwurd yn:</string>
+    <string name="deactivate_account_delete_checkbox">Ferjit alle berjochten dy’t ik ferstjoerd haw wannear myn account útskeakele is (Warskôging: hjirtroch kinne oare brûkers in ûnfolslein byld fan petearen krije)</string>
+    <string name="deactivate_account_title">Account deaktivearje</string>
     <string name="dialog_user_consent_submit">No besjen</string>
-    <string name="dialog_user_consent_content">Om de %1$s thústsjinner brûken te blieuwen mast de betingsten besjen en befestigje.</string>
+    <string name="dialog_user_consent_content">Om de %1$s-thússerver brûke te bliuwen, moatte jo de betingsten lêze en befêstigje.</string>
     <string name="forget_room">Keamer ferjitte</string>
     <string name="reason_colon">Reden: %1$s</string>
-    <string name="has_been_banned">Do binst út %1$s weiballe troch %2$s</string>
+    <string name="has_been_banned">%2$s hat jo út %1$s ferballe</string>
     <string name="identity_server_set_default_submit">%1$s Brûke</string>
-    <string name="call_ring">Skilje…</string>
+    <string name="call_ring">Belje…</string>
     <string name="call_transfer_users_tab_title">Brûkers</string>
     <string name="command_description_emote">Aksje sjen litte</string>
-    <string name="notice_member_no_changes_by_you">Do hast neat feroare</string>
-    <string name="notice_room_topic_removed_by_you">Do hast it keamerûnderwerp fuortsmiten</string>
-    <string name="notice_room_topic_removed">%1$s hat it keamerûnderwerp fuortsmiten</string>
-    <string name="notice_room_name_removed_by_you">Do hast de keamernamme fuortsmiten</string>
-    <string name="notice_room_name_removed">%1$s hat de keamernamme fuortsmiten</string>
-    <string name="notice_room_kick_with_reason">%1$s hat %2$s der út skopt. Reden: %3$s</string>
-    <string name="notice_room_kick_with_reason_by_you">Do hast %1$s fuortskopt. Reden: %2$s</string>
-    <string name="notice_direct_room_update_by_you">Do hast hjir fernijd.</string>
+    <string name="notice_member_no_changes_by_you">Jo hawwe neat wizige</string>
+    <string name="notice_room_topic_removed_by_you">Jo hawwe it keamerûnderwerp fuortsmiten</string>
+    <string name="notice_room_topic_removed">%1$s hat it petearûnderwerp fuortsmiten</string>
+    <string name="notice_room_name_removed_by_you">Jo hawwe de keamernamme fuortsmiten</string>
+    <string name="notice_room_name_removed">%1$s hat de petearnamme fuortsmiten</string>
+    <string name="notice_room_kick_with_reason">%1$s hat %2$s der útskopt. Reden: %3$s</string>
+    <string name="notice_room_kick_with_reason_by_you">Jo hawwe %1$s der útskopt. Reden: %2$s</string>
+    <string name="notice_direct_room_update_by_you">Jo hawwe hjir bywurke.</string>
     <string name="notice_direct_room_update">%s is hjir fernijd.</string>
-    <string name="notice_placed_voice_call_by_you">Do hast skille.</string>
+    <string name="notice_placed_voice_call_by_you">Jo hawwe in audiopetear iepene.</string>
     <string name="choose_locale_loading_locales">Beskikbere talen ophelje…</string>
     <string name="choose_locale_other_locales_title">Oare beskikbere talen</string>
     <string name="command_description_topic">Jou it ûnderwerp fan de keamer oan</string>
     <string name="report_content_spam">Dit is spam</string>
-    <string name="uploads_files_no_result">Der befyne sich gjin triemen yn disse keamer</string>
-    <string name="uploads_files_title">TRIEMEN</string>
-    <string name="uploads_media_no_result">Der befynt sich gjin media yn disse keamer</string>
+    <string name="uploads_files_no_result">Der binne gjin bestannen yn dizze keamer</string>
+    <string name="uploads_files_title">BESTANNEN</string>
+    <string name="uploads_media_no_result">Der is gjin media yn dizze keamer</string>
     <string name="uploads_media_title">MEDIA</string>
     <string name="rotate_and_crop_screen_title">Omdraaie en bysnije</string>
     <string name="attachment_type_sticker">Sticker</string>
     <string name="attachment_type_audio">Lûd</string>
     <string name="attachment_type_camera">Kamera</string>
     <string name="attachment_type_contact">Kontakt</string>
-    <string name="attachment_type_file">Triem</string>
+    <string name="attachment_type_file">Bestân</string>
     <string name="attachment_type_dialog_title">Ôfbylding tafoege út</string>
     <string name="error_attachment">In flater die sich foar wylst it taheaksel ophelle waard.</string>
     <string name="a11y_jump_to_bottom">Spring nei it ein</string>
@@ -514,43 +515,43 @@
     <string name="a11y_video">Fideo</string>
     <string name="settings_select_language">Taal útsykje</string>
     <string name="settings_interface_language">Taal</string>
-    <string name="disabled_integration_dialog_content">Skakel \'integraasjes tastean\' yn Ynstellings yn om dit te dwaan.</string>
-    <string name="disabled_integration_dialog_title">Integraasjes bin útskakele</string>
-    <string name="settings_integration_manager">Integraasje Behearder</string>
-    <string name="settings_integration_allow">Integraasje tastean</string>
-    <string name="settings_identity_server">Identiteits Tsjinner</string>
-    <string name="settings_home_server">Thús Tsjinner</string>
-    <string name="settings_logged_in">Ynloggd as</string>
+    <string name="disabled_integration_dialog_content">Skeakelje yn Ynstellingen ‘Yntegraasjes tastean’ yn om dit te dwaan.</string>
+    <string name="disabled_integration_dialog_title">Yntegraasjes binne útskeakele</string>
+    <string name="settings_integration_manager">Yntegraasjebehearder</string>
+    <string name="settings_integration_allow">Yntegraasjes tastean</string>
+    <string name="settings_identity_server">Identiteitsserver</string>
+    <string name="settings_home_server">Thússerver</string>
+    <string name="settings_logged_in">Oanmeld as</string>
     <string name="devices_delete_submit_button_label">Ferstjoere</string>
     <string name="devices_delete_pswd">Wachtwurd:</string>
     <string name="devices_delete_dialog_title">Authentikaasje</string>
-    <string name="devices_delete_dialog_text">Disse operaasje hat oanfullende authentikaasje nedich.
-\nFier dyn wachtwurd yn om troch te gean.</string>
+    <string name="devices_delete_dialog_text">Dizze operaasje hat oanfoljende autentikaasje nedich.
+\nFier jo wachtwurd yn om troch te gean.</string>
     <string name="devices_details_last_seen_title">Foar it letst sjûn</string>
-    <string name="devices_details_device_name">Iepenbiere Namme Feroarje</string>
-    <string name="devices_details_name_title">Iepenbiere Namme</string>
+    <string name="devices_details_device_name">Iepenbiere namme wizigje</string>
+    <string name="devices_details_name_title">Iepenbiere namme</string>
     <string name="devices_details_id_title">ID</string>
-    <string name="devices_details_dialog_title">Sesje informaasje</string>
+    <string name="devices_details_dialog_title">Sesjeynformaasje</string>
     <string name="settings_data_save_mode">Databesparjende modus</string>
     <string name="startup_notification_fdroid_battery_optim_button_grant">Tastimming jaan</string>
     <string name="startup_notification_privacy_button_other">In oare opsje kieze</string>
     <string name="startup_notification_privacy_button_grant">Tastimming jaan</string>
-    <string name="settings_discovery_manage">Dyn sichtberens ynstellings beheare.</string>
-    <string name="settings_discovery_category">Sichtberens</string>
+    <string name="settings_discovery_manage">Jo ûntdekynstellingen beheare.</string>
+    <string name="settings_discovery_category">Untdekke</string>
     <string name="settings_opt_in_of_analytics_ok">Ja, ik wol graach helpe!</string>
     <string name="settings_phone_number">Tillefoan nûmer</string>
     <string name="settings_general_title">Algemien</string>
     <string name="settings_devices_list">Sesjes</string>
     <string name="settings_pin_unread_messages">Keamers mei net lézen berjochten festsette</string>
     <string name="settings_rageshake">Lilkensskodzje</string>
-    <string name="settings_developer_mode_summary">De ûntwikkelders modus jout ûnsichtbere funksjes frei, en kin de applikaasje minder stabiel meitsje. Allinich foar ûntwikkelders!</string>
-    <string name="settings_developer_mode">Ûntwikkelders modus</string>
+    <string name="settings_developer_mode_summary">De ûntwikkelersmodus jout ûnsichtbere funksjes frij, en kin de applikaasje minder stabyl meitsje. Allinnich foar ûntwikkelers!</string>
+    <string name="settings_developer_mode">Untwikkelersmodus</string>
     <string name="resource_limit_contact_action">Kontakt Opnimme Mei Behearder</string>
-    <string name="report_content_inappropriate">Dit is tapasselik</string>
+    <string name="report_content_inappropriate">Dit is ûnfoech</string>
     <string name="pause_video">Skoftsje</string>
-    <string name="play_video">Ôfspylje</string>
+    <string name="play_video">Ofspylje</string>
     <string name="identity_server_set_alternative_submit">Ferstjoere</string>
-    <string name="identity_server_not_defined">Do brûkst gjin Identiteits Tsjinner</string>
+    <string name="identity_server_not_defined">Jo brûke gjin identiteitsserver</string>
     <string name="sas_error_unknown">Ûnbekende flater</string>
     <string name="sas_verification_request_notification_channel">Interactieve Sesje Ferifikaasje</string>
     <string name="sas_cancelled_by_me">De ferifikaasje is ôfbrutsen.
@@ -558,39 +559,39 @@
     <string name="sas_cancelled_by_other">De oare partij hat de ferifikaasje ôfbrutsen.
 \n%s</string>
     <string name="sas_cancelled_dialog_title">Oanfraach Ôfbrutsen</string>
-    <string name="sas_verification_request_notification_channel_title">Kaai Ferifikaasje</string>
+    <string name="sas_verification_request_notification_channel_title">Kaaiferifikaasje</string>
     <string name="sas_legacy_verification_button_title">Brûk ferâldere ferifikaasje.</string>
-    <string name="sas_verifying_keys">Wurd der neat sjen litten\? Net eltse kliïnt kin mei interactieve ferifikaasje oerwei. Brûk ferâldere ferifikaasje.</string>
+    <string name="sas_verifying_keys">Wurdt der neat toand\? Net elke kliïnt kin mei ynteraktive ferifikaasje oerwei. Brûk ferâldere ferifikaasje.</string>
     <string name="sas_incoming_request_notif_title">Ferifikaasje oanfraach</string>
-    <string name="sas_incoming_request_notif_content">%s wol dyn sesje ferifiearje</string>
-    <string name="sas_verified_successful_description">Feilige berjochten mei disse brûker binne ein-oant-ein fersifere, en kin net troch tredde partijen lézen wurde.</string>
-    <string name="sas_verified_successful">Do hast disse sesje mei sukses ferifieare.</string>
+    <string name="sas_incoming_request_notif_content">%s wol jo sesje ferifiearje</string>
+    <string name="sas_verified_successful_description">Feilige berjochten mei dizze brûker binne end-to-end-fersifere en kinne net troch tredde partijen lêzen wurde.</string>
+    <string name="sas_verified_successful">Jo hawwe dizze sesje mei sukses ferifiearre.</string>
     <string name="sas_verified">Ferifieare!</string>
     <string name="sas_waiting_for_partner">Oan it wachtsjen op partner om te befêstigjen …</string>
     <string name="sas_view_request_action">Oanfraach besjen</string>
     <string name="settings_security_pin_code_use_biometrics_title">Biometry ynskakelje</string>
     <string name="settings_security_pin_code_title">PIN ynskakelje</string>
-    <string name="settings_security_application_protection_screen_title">Feiligens ynstelle</string>
+    <string name="settings_security_application_protection_screen_title">Beskerming ynstelle</string>
     <string name="settings_security_application_protection_summary">Tagong befeiligje troch in PIN en biometry te brûken.</string>
     <string name="settings_security_application_protection_title">Tagong befeiligje</string>
     <string name="auth_pin_forgot">PIN fergetten\?</string>
-    <string name="auth_pin_title">Dyn PIN ynfiere</string>
+    <string name="auth_pin_title">Jo pin-koade ynfiere</string>
     <string name="create_pin_confirm_title">PIN befestigje</string>
-    <string name="create_pin_title">Brûk in PIN foar feiligens</string>
-    <string name="too_many_pin_failures">Te folle flaters, do binst útlogd</string>
+    <string name="create_pin_title">Brûk in pinkoade foar befeiliging</string>
+    <string name="too_many_pin_failures">Te folle flaters, jo binne ôfmeld</string>
     <string name="room_alias_local_address_add">Lokaal adres tafoege</string>
     <string name="keys_backup_setup_step3_button_title_no_passphrase">Ik ha in kopy makke</string>
     <string name="keys_backup_setup_step3_please_make_copy">Graach in kopy meitsje</string>
-    <string name="keys_backup_setup_override_stop">Ophâlde</string>
+    <string name="keys_backup_setup_override_stop">Stopje</string>
     <string name="keys_backup_setup_step3_button_title">Klear</string>
-    <string name="keys_backup_setup_step2_text_title">Feiligje dyn reservekopy mei in Wachtwurdssin.</string>
-    <string name="keys_backup_setup_step1_manual_export">Kaaien mei de hân eksportearje</string>
-    <string name="keys_backup_setup_step1_advanced">(Avanseare)</string>
+    <string name="keys_backup_setup_step2_text_title">Befeiligje jo reservekopy mei in wachtwurd.</string>
+    <string name="keys_backup_setup_step1_manual_export">Kaaien hânmjittich eksportearje</string>
+    <string name="keys_backup_setup_step1_advanced">(Avansearre)</string>
     <string name="keys_backup_setup_step1_title">Reitsje jo fersifere gegevens nea kwyt</string>
     <string name="keys_backup_no_session_error">Gjin Matrix sesje beskikber</string>
-    <string name="template_keys_backup_passphrase_not_empty_error_message">Graach de wachtwurdssin fuortsmite ast wolst dot ${app_name} in nije herstel kaai foar dy oanmakket.</string>
+    <string name="template_keys_backup_passphrase_not_empty_error_message">Graach de wachtwurdsin fuortsmite as jo wolle dat ${app_name} in nije werstelkaai foar jo oanmakket.</string>
     <string name="passphrase_empty_error_message">Graach in wachtwurdssin ynfiere</string>
-    <string name="passphrase_passphrase_does_not_match">Wachtwurdssin komt net oerien</string>
+    <string name="passphrase_passphrase_does_not_match">Wachtwurden komme net oerien</string>
     <string name="passphrase_enter_passphrase">Wachtwurdssin ynfiere</string>
     <string name="passphrase_confirm_passphrase">Wachtwurdssin befestigje</string>
     <string name="passphrase_create_passphrase">Wachtwurdssin oanmeitsje</string>
@@ -598,8 +599,8 @@
     <string name="event_status_a11y_failed">Mislearre</string>
     <string name="settings_remove_three_pid_confirmation_content">%s fuortsmite\?</string>
     <string name="settings_security_pin_code_change_pin_title">PIN feroarje</string>
-    <string name="settings_advanced">Avanseare</string>
-    <string name="settings_notification_advanced">Avanseare Ynstellings Foar Notifikaasjes</string>
+    <string name="settings_advanced">Avansearre</string>
+    <string name="settings_notification_advanced">Avansearre notifikaasjeynstellingen</string>
     <string name="room_settings_forget">Ferjitte</string>
     <string name="room_settings_tag_pref_entry_favourite">Favorite</string>
     <string name="media_source_choose">Útsykje</string>
@@ -607,11 +608,11 @@
     <string name="settings_phone_number_country_error">Graach in lân útsykje</string>
     <string name="settings_select_country">Lân útsykje</string>
     <string name="passwords_do_not_match">Wachtwurden komme net oerien</string>
-    <string name="account_email_not_found_error">Dit emailadres koe net fûn wurde.</string>
-    <string name="account_email_already_used_error">Dit emailadres wurd ol brûkt.</string>
-    <string name="account_phone_number_already_used_error">Dit telefoannûmer wurd ol brûkt.</string>
-    <string name="settings_emails_and_phone_numbers_title">Emails en telefoannûmers</string>
-    <string name="settings_password_updated">Dyn wachtwurd is fernijd</string>
+    <string name="account_email_not_found_error">Dit e-mailadres koe net fûn wurde.</string>
+    <string name="account_email_already_used_error">Dit e-mailadres is al yn gebrûk.</string>
+    <string name="account_phone_number_already_used_error">Dit telefoannûmer is al yn gebrûk.</string>
+    <string name="settings_emails_and_phone_numbers_title">E-mailadressen en telefoannûmers</string>
+    <string name="settings_password_updated">Jo wachtwurd is bywurke</string>
     <string name="settings_fail_to_update_password_invalid_current_password">It wachtwurd is net jildich</string>
     <string name="settings_fail_to_update_password">Fernijen fan it wachtwurd is mislearre</string>
     <string name="settings_change_password_submit">Wachtwurd Fernije</string>
@@ -625,46 +626,46 @@
     <string name="room_settings_topic">Ûnderwerp</string>
     <string name="room_settings_room_read_history_rules_pref_dialog_title">Wa kin de skiednis lêze\?</string>
     <string name="room_alias_local_address_title">Lokaal Adres</string>
-    <string name="room_settings_room_access_entry_anyone_with_link_apart_guest">Eltsenien dyt in link nei disse keamer hat, mar gjin gasten</string>
+    <string name="room_settings_room_access_entry_anyone_with_link_apart_guest">Elkenien dy’t in keppeling nei dizze keamer hat, mar gjin gasten</string>
     <string name="room_settings_room_access_private_title">Privee</string>
     <string name="room_settings_room_access_public_title">Iepenbier</string>
-    <string name="room_settings_room_access_entry_knock">Eltsenien kin by disse keamer oankopje, leden kinne don akseptearje as ôfslaan</string>
-    <string name="room_settings_room_access_entry_anyone_with_link_including_guest">Eltsenien dyt in link nei disse keamer hat, sels gasten</string>
-    <string name="no_ignored_users">Do hast gjin brûkers negearre</string>
+    <string name="room_settings_room_access_entry_knock">Elkenien kin by dizze keamer oanklopje, leden kinne dan akseptearje of wegerje</string>
+    <string name="room_settings_room_access_entry_anyone_with_link_including_guest">Elkenien dy’t in keppeling nei dizze keamer hat, ynklusyf gasten</string>
+    <string name="no_ignored_users">Jo hawwe gjin brûkers negearre</string>
     <string name="settings_ignored_users">Negearre brûkers</string>
-    <string name="preference_voice_and_video">Stim &amp; Fideo</string>
+    <string name="preference_voice_and_video">Stim &amp; fideo</string>
     <string name="settings_advanced_settings">Avansearre ynstellingen</string>
     <string name="login_server_other_text">Oanpaste en avansearre ynstellingen</string>
-    <string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">Akkount Tafoegje</string>
-    <string name="settings_troubleshoot_test_bing_settings_title">Oanpaste Ynstellingen.</string>
+    <string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">Account tafoegje</string>
+    <string name="settings_troubleshoot_test_bing_settings_title">Oanpaste ynstellingen.</string>
     <string name="settings_troubleshoot_test_device_settings_quickfix">Ynskeakelje</string>
     <string name="settings_troubleshoot_test_account_settings_quickfix">Ynskeakelje</string>
-    <string name="settings_troubleshoot_test_account_settings_success">Notifikaasjes binne ynskeakele foar dyn akkount.</string>
-    <string name="settings_troubleshoot_test_account_settings_title">Akkount Ynstellingen.</string>
+    <string name="settings_troubleshoot_test_account_settings_success">Notifikaasjes binne foar jo account ynskeakele.</string>
+    <string name="settings_troubleshoot_test_account_settings_title">Accountynstellingen.</string>
     <string name="open_settings">Ynstellingen Iepenje</string>
-    <string name="settings_troubleshoot_test_system_settings_success">Notifikaasjes binne ynskeakele yn de systeem ynstellingen.</string>
+    <string name="settings_troubleshoot_test_system_settings_success">Notifikaasjes binne ynskeakele yn de systeemynstellingen.</string>
     <string name="settings_troubleshoot_test_system_settings_title">Systeem Ynstellingen.</string>
     <string name="settings_troubleshoot_diagnostic_run_button_title">Tests Útfiere</string>
     <string name="settings_phone_numbers">Telefoannûmers</string>
     <string name="settings_emails">E-mailadressen</string>
     <string name="settings_add_3pid_confirm_password_title">Wachtwurd befêstigje</string>
-    <string name="settings_app_info_link_summary">Applikaasje informaasje yn de systeem ynstellingen sjen litte.</string>
-    <string name="settings_app_info_link_title">Applikaasje informaasje</string>
+    <string name="settings_app_info_link_summary">Applikaasjeynformaasje yn de systeemynstellingen toane.</string>
+    <string name="settings_app_info_link_title">Applikaasjeynformaasje</string>
     <string name="settings_add_phone_number">Telefoannûmer tafoegje</string>
-    <string name="settings_phone_number_empty">Der is gjin telefoannûmer tafoege oan syn akkount</string>
+    <string name="settings_phone_number_empty">Der is gjin telefoannûmer oan jo account tafoege</string>
     <string name="settings_add_email_address">E-mailadres tafoegje</string>
     <string name="settings_email_address">Email</string>
     <string name="room_sliding_menu_settings">Ynstellingen</string>
-    <string name="room_settings_leave_conversation">Petear Ferlitte</string>
+    <string name="room_settings_leave_conversation">Petear ferlitte</string>
     <string name="room_settings_direct_chat">Direkt Petear</string>
     <string name="room_settings_all_messages">Alle berjochten</string>
     <string name="room_settings_all_messages_noisy">Alle berjochten (lûd)</string>
     <string name="room_details_settings">Ynstellingen</string>
-    <string name="room_permissions_change_settings">Ynstellingen feroarje</string>
-    <string name="room_settings_permissions_title">Keamer rjochten</string>
-    <string name="notice_room_server_acl_updated_title_by_you">Do hast de tsjinner ACLs foar dizze keamer feroare.</string>
-    <string name="notice_room_server_acl_updated_title">%s hat de server-ACL\'s foar dizze keamer feroare.</string>
-    <string name="notice_avatar_url_changed_by_you">Do hast dyn profyl ôfbylding feroare</string>
+    <string name="room_permissions_change_settings">Ynstellingen wizigje</string>
+    <string name="room_settings_permissions_title">Petearrjochten</string>
+    <string name="notice_room_server_acl_updated_title_by_you">Jo hawwe de server-ACL’s foar dizze keamer wizige.</string>
+    <string name="notice_room_server_acl_updated_title">%s hat de server-ACL’s foar dizze keamer wizige.</string>
+    <string name="notice_avatar_url_changed_by_you">Jo hawwe jo profylôfbylding wizige</string>
     <string name="send_suggestion_failed">Koe de suggestje net ferstjoere (%s)</string>
     <string name="send_suggestion_sent">Dankewol, it ferstjoeren fan de suggestje is slagge</string>
     <string name="send_suggestion_report_placeholder">Skriuw jo suggestje hjir</string>
@@ -682,13 +683,13 @@
     <string name="room_list_rooms_empty_title">Keamers</string>
     <string name="room_list_catchup_welcome_title">Wolkom thús!</string>
     <string name="invited_by">Útnûge troch %s</string>
-    <string name="send_you_invite">Hat jo in ûtnoeging stjoerd</string>
+    <string name="send_you_invite">Hat jo in útnûging stjoerd</string>
     <string name="room_list_empty">Gean in keamer binnen om de app te brûken.</string>
     <string name="global_retry">Opnij probearje</string>
     <string name="edit">Feroarje</string>
     <string name="sas_error_m_user_error">Brûkers komme net oerien</string>
     <string name="sas_error_m_key_mismatch">Kaaien komme net oerien</string>
-    <string name="sas_error_m_invalid_message">Der is en ûnjildich berjocht ûntfong</string>
+    <string name="sas_error_m_invalid_message">Der is in ûnjildich berjocht ûntfongen</string>
     <string name="sas_error_m_unexpected_message">De sesje hat ûnferwachts in berjocht ûntfong</string>
     <string name="sas_error_m_mismatched_sas">De SAS kaam net oerien</string>
     <string name="sas_error_m_unknown_transaction">De sesje wit neat fan dy transaksje</string>
@@ -700,10 +701,10 @@
     <string name="keys_backup_settings_delete_confirm_title">Back-up Fuortsmite</string>
     <string name="keys_backup_settings_delete_backup_error">Koe de back-up net fuortsmite (%s)</string>
     <string name="keys_backup_settings_deleting_backup">Back-up oan it fuortsmiten…</string>
-    <string name="keys_backup_restoring_waiting_message">Back-up werom sette:</string>
+    <string name="keys_backup_restoring_waiting_message">Reservekopy wurdt wersteld:</string>
     <string name="keys_backup_setup_skip_title">Binne jo der wis fan\?</string>
     <string name="keys_backup_setup_override_replace">Ferfange</string>
-    <string name="keys_backup_setup_step3_save_button_title">As bestân opslaan</string>
+    <string name="keys_backup_setup_step3_save_button_title">As bestân bewarje</string>
     <string name="keys_backup_setup_step3_share_recovery_file">Diele</string>
     <string name="passphrase_passphrase_too_weak">Wachtwurdssin is net sterk genôch</string>
     <string name="keys_backup_setup_step3_success_title">Slagge!</string>
@@ -713,7 +714,7 @@
     <string name="no_users_placeholder">Gjin brûkers</string>
     <string name="group_details_rooms">Keamers</string>
     <string name="group_details_people">Minsken</string>
-    <string name="group_details_home">Thús</string>
+    <string name="group_details_home">Startskerm</string>
     <string name="community_id_hint">foarbyld</string>
     <string name="community_name_hint">Foarbyld</string>
     <string name="create">Oanmeitsje</string>
@@ -741,7 +742,7 @@
     <string name="tiny">Hiel lyts</string>
     <string name="font_size">Grutte fan it lettertype</string>
     <string name="notification_sender_me">Ik</string>
-    <string name="notification_new_invitation">Nije Útnoeging</string>
+    <string name="notification_new_invitation">Nije útnûging</string>
     <string name="notification_new_messages">Nij Berjocht</string>
     <string name="notification_unknown_room_name">Keamer</string>
     <string name="notification_unknown_new_event">Nij Evenemint</string>
@@ -758,35 +759,35 @@
     </plurals>
     <plurals name="notification_invitations">
         <item quantity="one">%d útnûging</item>
-        <item quantity="other">%d útnoegingen</item>
+        <item quantity="other">%d útnûgingen</item>
     </plurals>
     <plurals name="notification_unread_notified_messages_in_room_rooms">
         <item quantity="one">%d keamer</item>
         <item quantity="other">%d keamers</item>
     </plurals>
     <string name="lock_screen_hint">Typ hjir…</string>
-    <string name="directory_add_a_new_server_error_already_added">De tsjinner stiet al yn de list</string>
-    <string name="directory_add_a_new_server_error">Kin dizze tsjinner, as de rômte list fan dizze tsjinner net fine</string>
-    <string name="directory_add_a_new_server_prompt">Fier de namme yn fan de tsjinner dy jo ûntdekke wolle.</string>
-    <string name="directory_add_a_new_server">In nije tsjinner tafoegje</string>
-    <string name="directory_your_server">Jo tsjinner</string>
-    <string name="directory_server_all_rooms_on_server">Alle keamers op %s tsjinner</string>
-    <string name="directory_server_placeholder">Tsjinner namme</string>
+    <string name="directory_add_a_new_server_error_already_added">Dizze server stiet al yn de list</string>
+    <string name="directory_add_a_new_server_error">Kin dizze server of de keamerlist fan dizze server net fine</string>
+    <string name="directory_add_a_new_server_prompt">Fier de namme yn fan de server dy’t jo ûntdekke wolle.</string>
+    <string name="directory_add_a_new_server">In nije server tafoegje</string>
+    <string name="directory_your_server">Jo server</string>
+    <string name="directory_server_all_rooms_on_server">Alle petearen op server %s</string>
+    <string name="directory_server_placeholder">Servernamme</string>
     <string name="unknown_devices_alert_title">Keamer hat ûnbekend sesjes</string>
-    <string name="encryption_information_verify_key_match">Ik befêstigje dat de kaaien oerien komme</string>
+    <string name="encryption_information_verify_key_match">Ik befêstigje dat de kaaien oerienkomme</string>
     <string name="encryption_information_verify_device_warning2">As dit net oerienkomt, kin de feiligens fan jo kommunikaasje kompromittearre wêze.</string>
-    <string name="encryption_information_verify_device_warning">Befêstigje troch dit te fergelykjen mei Brûkers Ynstellingen fan jo oare sesje:</string>
-    <string name="encryption_information_unblock">Fan de swarte list ôf helje</string>
-    <string name="encryption_information_verify_device">Sesje ferifiearre</string>
-    <string name="encryption_information_blocked">Op de swarte list set</string>
+    <string name="encryption_information_verify_device_warning">Befêstigje troch dit te fergelykjen mei de Brûkersynstellingen fan jo oare sesje:</string>
+    <string name="encryption_information_unblock">Deblokkearringslist</string>
+    <string name="encryption_information_verify_device">Sesje ferifiearje</string>
+    <string name="encryption_information_blocked">Blokkearre</string>
     <string name="encryption_information_verified">Ferifiearre</string>
-    <string name="encryption_information_not_verified">Net Ferifiearre</string>
-    <string name="encryption_information_decryption_error">Ûntsiferings flater</string>
-    <string name="encryption_information_session_id">Sesje ID</string>
+    <string name="encryption_information_not_verified">Net ferifiearre</string>
+    <string name="encryption_information_decryption_error">Untsiferingsflater</string>
+    <string name="encryption_information_session_id">Sesje-ID</string>
     <string name="encryption_information_algorithm">Algoritme</string>
     <string name="settings_theme">Tema</string>
     <string name="directory_title">Oersjoch</string>
-    <string name="room_settings_set_main_address">As haad adres ynstelle</string>
+    <string name="room_settings_set_main_address">As haadadres ynstelle</string>
     <string name="room_settings_addresses_add_new_address">Nij adres (bygelyks #foo:matrix.org)</string>
     <string name="room_settings_labs_end_to_end_warnings">Jo moatte útlogge om fersifering ynskeakelje te kinnen.</string>
     <string name="room_settings_labs_end_to_end_is_active">Ein-oan-Ein fersifering is ynskeakele</string>
@@ -800,72 +801,72 @@
     <string name="room_alias_published_alias_add_manually_submit">Publisearje</string>
     <string name="room_settings_room_access_title">Keamer tagong</string>
     <string name="room_settings_room_access_rules_pref_dialog_title">Wa hat tagong ta dizze keamer\?</string>
-    <string name="room_settings_room_read_history_rules_pref_title">Keamer Skiednis Lêsberheid</string>
+    <string name="room_settings_room_read_history_rules_pref_title">Tagong ta de petearskiednis</string>
     <string name="room_settings_room_access_rules_pref_title">Keamer Tagong</string>
     <string name="room_settings_directory_visibility">Dizze keamer yn it keamer oersjoch sjen litte</string>
-    <string name="room_settings_category_access_visibility_title">Tagong en sichtberens</string>
+    <string name="room_settings_category_access_visibility_title">Tagonklikheid en sichtberheid</string>
     <string name="room_settings_tag_pref_entry_low_priority">Lege prioriteit</string>
     <string name="settings_default_compression">Standert komprimearing</string>
     <string name="settings_media">Media</string>
     <string name="settings_phone_number_verification_error_empty_code">In ativaasje koade ynfiere</string>
     <string name="settings_phone_number_label">Telefoan nûmer</string>
     <string name="settings_delete_threepid_confirmation">Binne jo der wis fan dat jo de %1$s %2$s fuort smite wolle\?</string>
-    <string name="settings_emails_and_phone_numbers_summary">E-mail adressen en telefoan nûmers dy oan jo Matrix account keppele binne behearre</string>
+    <string name="settings_emails_and_phone_numbers_summary">E-mailadressen en telefoannûmers dy’t oan jo Matrix-account keppele binne beheare</string>
     <string name="account_email_error">Der die harren in flater foar wylst jo e-mail adres ferifiearre waard.</string>
-    <string name="settings_old_password">Hjoeddeistich wachtwurd</string>
+    <string name="settings_old_password">Aktuele wachtwurd</string>
     <string name="devices_details_last_seen_format">%1$s @ %2$s</string>
     <string name="settings_deactivate_my_account">Myn account deaktivearje</string>
     <string name="settings_deactivate_account_section">Account deaktivearje</string>
     <string name="settings_secure_backup_manage">Behearre</string>
     <string name="settings_send_message_with_enter">Berjochten mei enter ferstjoere</string>
     <string name="settings_vibrate_on_mention">Trilje wannear jo neamd wurde</string>
-    <string name="settings_show_avatar_display_name_changes_messages">Account eveneminten sjen litte</string>
-    <string name="settings_show_join_leave_messages">Sjen litte wannear oft minsken de keamer yn kaam binne, as der út gien binne</string>
-    <string name="settings_chat_effects_description">Brûk it /confetti kommando as ferstjoer in berjocht mei ❄️ as 🎉</string>
-    <string name="settings_chat_effects_title">Chat effekten sjen litte</string>
-    <string name="settings_show_read_receipts">Sjen kinne dat berjochten lêzen binne</string>
+    <string name="settings_show_avatar_display_name_changes_messages">Accountbarrens toane</string>
+    <string name="settings_show_join_leave_messages">Toane wannear oft minsken de keamer yn kaam binne, of der útgien binne</string>
+    <string name="settings_chat_effects_description">Brûk it kommando /confetti of stjoer in berjocht mei ❄️ of 🎉</string>
+    <string name="settings_chat_effects_title">Chateffekten toane</string>
+    <string name="settings_show_read_receipts">Lêsbefêstigingen toane</string>
     <string name="settings_send_typing_notifs_summary">Lit oare minsken witte dat jo oan it typen binne.</string>
-    <string name="settings_send_typing_notifs">Typ notifikaasjes ferstjoere</string>
-    <string name="settings_always_show_timestamps">Tiid stimpels foar alle berjochten sjen litte</string>
-    <string name="settings_cryptography_manage_keys">Fersifering Kaai Behear</string>
+    <string name="settings_send_typing_notifs">Typenotifikaasjes ferstjoere</string>
+    <string name="settings_always_show_timestamps">Tiidstimpels foar alle berjochten toane</string>
+    <string name="settings_cryptography_manage_keys">Behear fan kryptografyske kaaien</string>
     <string name="settings_cryptography">Fersifering</string>
     <string name="settings_other">Oare ynstellingen</string>
     <string name="settings_notifications">Notifikaasjes</string>
-    <string name="settings_user_settings">Brûkers ynstellingen</string>
-    <string name="settings_olm_version">olm ferzje</string>
+    <string name="settings_user_settings">Brûkersynstellingen</string>
+    <string name="settings_olm_version">olm-ferzje</string>
     <string name="settings_version">Ferzje</string>
     <string name="settings_background_fdroid_sync_mode">Eftergrûn Syngronisaasje Modus</string>
     <string name="settings_background_fdroid_sync_mode_battery">Optimalisearje foar batterij gebrûk</string>
     <string name="settings_invited_to_room">Wannear ik útnûge wurd foar in keamer</string>
-    <string name="settings_silent_notifications_preferences">Stille Notifikaasjes Ynstelle</string>
-    <string name="settings_notification_privacy_metadata">• Notifikaasjes befetsje allinich metadata</string>
+    <string name="settings_silent_notifications_preferences">Stille notifikaasjes ynstelle</string>
+    <string name="settings_notification_privacy_metadata">• Notifikaasjes befetsje allinnich metadata</string>
     <string name="settings_notification_privacy_fcm">• Notifikaasjes wurde mei Firebase Cloud Messaging ferstjoerd</string>
     <string name="settings_notification_privacy_need_permission">Dizze applikaasje hat tastimming nedich om op de eftergrûn te starten</string>
     <string name="settings_troubleshoot_test_bg_restricted_quickfix">Restriksjes útskeakelje</string>
-    <string name="settings_notification_privacy_message_content_not_shown">• Notifikaasje sil de <b>ynhâld fan it berjocht net sjen litte</b></string>
-    <string name="settings_system_preferences_summary">LED kleur útsykje, triljen, lûd…</string>
-    <string name="settings_noisy_notifications_preferences">Lûde Notifikaasjes Ynstelle</string>
+    <string name="settings_notification_privacy_message_content_not_shown">• Notifikaasjes sille de <b>ynhâld fan it berjocht net toane</b></string>
+    <string name="settings_system_preferences_summary">LED-kleur, triljen, lûd…</string>
+    <string name="settings_noisy_notifications_preferences">Lûde notifikaasjes ynstelle</string>
     <string name="settings_turn_screen_on">It skerm foar 3 sekonden ynskeakelje</string>
     <string name="settings_enable_this_device">Notifikaasjes foar dizze sesje ynskeakelje</string>
-    <string name="settings_enable_all_notif">Notifikaasjes foar dit account ynskeakelje</string>
+    <string name="settings_enable_all_notif">Notifikaasjes foar dizze account ynskeakelje</string>
     <string name="settings_notification_ringtone">Notifikaasje lûd</string>
     <string name="settings_notification_privacy_normal">Gewoan</string>
     <string name="settings_troubleshoot_test_foreground_service_started_quickfix">Tsjinst Starte</string>
-    <string name="settings_troubleshoot_test_foreground_service_started_title">Notifikaasje Tsjinst</string>
+    <string name="settings_troubleshoot_test_foreground_service_started_title">Notifikaasjetsjinst</string>
     <string name="settings_troubleshoot_test_bing_settings_quickfix">Ynstellingen Kontrolearje</string>
     <string name="settings_troubleshoot_test_device_settings_title">Sesje Ynstellingen.</string>
     <string name="settings_troubleshoot_diagnostic_running_status">Oan it útfieren… (%1$d of %2$d)</string>
-    <string name="settings_profile_picture">Profyl Ôfbylding</string>
+    <string name="settings_profile_picture">Profylôfbylding</string>
     <string name="room_sliding_menu_version_x">Ferzje %s</string>
     <string name="room_sliding_menu_version">Ferzje</string>
-    <string name="room_recents_invites">ÚTNOEGINGEN</string>
+    <string name="room_recents_invites">ÚTNÛGINGEN</string>
     <string name="room_recents_low_priority">LEGE PRIORITEIT</string>
     <string name="room_recents_conversations">KEAMERS</string>
     <string name="room_recents_favourites">FAVORITEN</string>
     <string name="room_recents_directory">OERSJOCH</string>
     <string name="tab_title_search_rooms">KEAMERS</string>
     <string name="search_no_results">Gjin resultaten</string>
-    <string name="room_event_action_cancel_download">Delheljen Ôfbrekke</string>
+    <string name="room_event_action_cancel_download">Download annulearje</string>
     <string name="room_details_people">Minsken</string>
     <string name="room_details_title">Keamer Details</string>
     <string name="room_details_files">Bestannen</string>
@@ -873,73 +874,73 @@
     <string name="room_details_people_invited_group_name">ÚTNÛGE</string>
     <string name="room_permissions_change_permissions">Permisjes feroarje</string>
     <string name="room_permissions_change_room_name">Keamer namme feroarje</string>
-    <string name="room_permissions_change_history_visibility">Skiednis sichtberens feroarje</string>
+    <string name="room_permissions_change_history_visibility">Sichtberens skiednis wizigje</string>
     <string name="room_permissions_enable_room_encryption">Keamer fersifering ynskeakelje</string>
     <string name="room_permissions_change_main_address_for_the_room">Haad adres fan de keamer feroarje</string>
     <string name="room_permissions_change_room_avatar">Keamer ôfbylding feroarje</string>
     <string name="room_permissions_notify_everyone">Elkenien op de hichte bringe</string>
-    <string name="room_permissions_remove_messages_sent_by_others">Berjochten dy troch oaren ferstjoerd binne fuort smite</string>
+    <string name="room_permissions_remove_messages_sent_by_others">Berjochten dy’t troch oaren ferstjoerd binne fuortsmite</string>
     <string name="room_permissions_ban_users">Brûkers ferbalje</string>
     <string name="room_permissions_kick_users">Brûkers der út skoppe</string>
     <string name="room_permissions_invite_users">Brûkers útnûgje</string>
     <string name="room_permissions_send_messages">Berjochten ferstjoere</string>
     <string name="room_permissions_default_role">Standert rol</string>
     <string name="room_permissions_title">Permisjes</string>
-    <string name="ssl_remain_offline">Negearre</string>
-    <string name="ssl_logout_account">Útlogge</string>
+    <string name="ssl_remain_offline">Negearje</string>
+    <string name="ssl_logout_account">Ofmelde</string>
     <string name="ssl_do_not_trust">Net fertrouwe</string>
     <string name="ssl_trust">Fertrouwe</string>
     <string name="room_message_file_not_found">Bestân net fûn</string>
     <string name="room_delete_unsent_messages">Net ferstjoerde berjochten fuortsmite</string>
     <string name="room_resend_unsent_messages">Net ferstjoerde berjochten opnij ferstjoere</string>
-    <string name="room_prompt_cancel">Alles ôfbrekke</string>
+    <string name="room_prompt_cancel">Alles annulearje</string>
     <string name="room_prompt_resend">Alles opnij ferstjoere</string>
-    <string name="room_unsent_messages_notification">Berjocht net ferstjoerd. %1$s as %2$s no\?</string>
-    <string name="room_offline_notification">Ferbining mei de tsjinner is ferlern.</string>
+    <string name="room_unsent_messages_notification">Berjochten net ferstjoerd. No %1$s of %2$s\?</string>
+    <string name="room_offline_notification">Ferbining mei de server is ferbrutsen.</string>
     <string name="room_message_placeholder_reply_to_not_encrypted">In reaksje ferstjoere (net fersifere)…</string>
     <string name="room_message_placeholder_reply_to_encrypted">In fersifere reaksje ferstjoere…</string>
     <string name="room_message_placeholder_not_encrypted">In berjocht ferstjoere (net fersifere)…</string>
     <string name="room_message_placeholder_encrypted">In fersifere berjocht ferstjoere…</string>
-    <string name="people_search_filter_text">Allinich Matrix brûkers</string>
-    <string name="room_participants_action_cancel_invite_title">Útnoeging ôfbrekke</string>
-    <string name="room_participants_action_unignore">Net mear negearre</string>
+    <string name="people_search_filter_text">Allinnich Matrix-brûkers</string>
+    <string name="room_participants_action_cancel_invite_title">Utnûging annulearje</string>
+    <string name="room_participants_action_unignore">Net mear negearje</string>
     <string name="room_participants_action_ignore_title">Brûker negearre</string>
-    <string name="room_participants_action_unignore_title">Brûker net mear negearre</string>
-    <string name="room_participants_action_ignore">Negearre</string>
+    <string name="room_participants_action_unignore_title">Brûker net mear negearje</string>
+    <string name="room_participants_action_ignore">Negearje</string>
     <string name="room_participants_power_level_demote">Degradearje</string>
-    <string name="room_participants_power_level_demote_warning_title">Jo sels degradearje\?</string>
-    <string name="room_participants_action_devices_list">Sesje list sjen litte</string>
-    <string name="room_participants_action_mention">Neame</string>
-    <string name="room_participants_action_set_admin">In administrator meitsje</string>
-    <string name="room_participants_action_set_moderator">In moderator meitsje</string>
-    <string name="room_participants_action_set_default_power_level">Werom sette nei gewoane brûker</string>
-    <string name="room_participants_action_kick">Der út skoppe</string>
+    <string name="room_participants_power_level_demote_warning_title">Josels degradearje\?</string>
+    <string name="room_participants_action_devices_list">Sesjelist toane</string>
+    <string name="room_participants_action_mention">Fermelde</string>
+    <string name="room_participants_action_set_admin">Behearder meitsje</string>
+    <string name="room_participants_action_set_moderator">Moderator meitsje</string>
+    <string name="room_participants_action_set_default_power_level">Weromsette nei gewoane brûker</string>
+    <string name="room_participants_action_kick">Der útskoppe</string>
     <string name="room_participants_action_ban">Ferbalje</string>
-    <string name="room_participants_action_cancel_invite">Útnoeging ôfbrekke</string>
-    <string name="room_participants_action_invite">Útnûgje</string>
+    <string name="room_participants_action_cancel_invite">Utnûging annulearje</string>
+    <string name="room_participants_action_invite">Utnûgje</string>
     <string name="room_participants_header_devices">SESJES</string>
-    <string name="room_participants_header_direct_chats">Direkte Berjochten</string>
+    <string name="room_participants_header_direct_chats">Direkte berjochten</string>
     <string name="room_participants_header_call">SKILJE</string>
-    <string name="room_participants_header_admin_tools">ADMINISTRAASJE ARK</string>
+    <string name="room_participants_header_admin_tools">BEHEARDERSARK</string>
     <string name="room_participants_ago">%1$s %2$s lyn</string>
-    <string name="room_participants_now">%1$s no</string>
-    <string name="room_participants_idle">Ôfwêzich</string>
+    <string name="room_participants_now">no %1$s</string>
+    <string name="room_participants_idle">Ofwêzich</string>
     <string name="room_participants_offline">Offline</string>
     <string name="room_participants_online">Online</string>
     <string name="room_participants_leave_prompt_msg">Binne jo der wis fan dat jo de keamer ferlitte wolle\?</string>
     <string name="room_participants_leave_prompt_title">Keamer ferlitte</string>
-    <string name="room_title_one_member">1 lid</string>
+    <string name="room_title_one_member">1 dielnimmer</string>
     <string name="room_sync_in_progress">Syngronisearje…</string>
-    <string name="continue_anyway">Dochs Trochgean</string>
-    <string name="media_slider_saved_message">Yn downloads opslaan\?</string>
-    <string name="media_slider_saved">Opslein</string>
-    <string name="media_picker_both_capture_title">In foto as fideo meitsje</string>
+    <string name="continue_anyway">Dochs trochgean</string>
+    <string name="media_slider_saved_message">Yn downloads bewarje\?</string>
+    <string name="media_slider_saved">Bewarre</string>
+    <string name="media_picker_both_capture_title">In foto of fideo meitsje</string>
     <string name="media_picker_cannot_record_video">Kin gjin fideo opnimme</string>
     <string name="call">Belje</string>
     <string name="attachment_remaining_time_minutes">%1$dm %2$ds</string>
     <string name="attachment_remaining_time_seconds">%d s</string>
-    <string name="attachment_cancel_download">It delheljen ôfbrekke\?</string>
-    <string name="e2e_re_request_encryption_key">Opnij de fersifering kaaien fan jo oare sesjes opfreegje.</string>
+    <string name="attachment_cancel_download">Downloaden annulearje\?</string>
+    <string name="e2e_re_request_encryption_key">De fersiferingskaaien fan jo oare sesjes opnij opfreegje.</string>
     <string name="login_error_unable_register_mail_ownership">Registrearjen mislearre: e-mail-eigendomsflater</string>
     <string name="login_error_network_error">Kin net oanmelde: netwurkflater</string>
     <string name="login_error_must_start_http">URL moat mei http[s]:// begjinne</string>
@@ -955,45 +956,45 @@
     <string name="sound_device_headset">Koptelefoan</string>
     <string name="sound_device_speaker">Lûdsprekker</string>
     <string name="call_failed_no_ice_use_alt">Probearje ris %s te brûken</string>
-    <string name="option_send_voice">Stimlûd ferstjoere</string>
+    <string name="option_send_voice">Spraakberjocht ferstjoere</string>
     <string name="start_video_call">Fideo-oprop begjinne</string>
     <string name="start_voice_call">Spraakoprop begjinne</string>
-    <string name="identity_url">URL identiteitsserver</string>
-    <string name="hs_client_url">API URL thússerver</string>
-    <string name="hs_url">URL thússerver</string>
+    <string name="identity_url">Identiteitsserver-URL</string>
+    <string name="hs_client_url">Thússerver API-URL</string>
+    <string name="hs_url">Thússerver-URL</string>
     <string name="send_bug_report_failed">It oanjaan fan in flater yn dizze applikaasje is net slagge (%s)</string>
     <string name="send_bug_report_sent">It oanjaan fan in flater yn dizze applikaasje is slagge</string>
     <string name="join_room">Keamer binnen gean</string>
     <string name="send_bug_report_progress">Foarútgong (%s%%)</string>
-    <string name="send_bug_report_app_crashed">Dizze applikaasje is de lêste kear fêstrûn. Wolle jo miskien it skerm iepenje om in flater yn dizze applikaasje oan te jaan\?</string>
-    <string name="send_bug_report_alert_message">It liket der op dat jo út lilkens mei jo telefoan skodzje. Wolle jo miskien it skerm iepenje om in flater yn dizze applikaasje oan te jaan\?</string>
+    <string name="send_bug_report_app_crashed">Dizze applikaasje is de lêste kear fêstrûn. Wolle jo dit melde\?</string>
+    <string name="send_bug_report_alert_message">It liket der op dat jo út lilkens mei jo telefoan skodzje. Wolle jo in probleem melde\?</string>
     <string name="spaces_header">Romten</string>
-    <string name="spaces_invited_header">Utnûgingen</string>
-    <string name="settings_room_directory_show_all_rooms_summary">Alle keamers yn it keameroersjoch toane, ek keamers mei ynhâld foar folwoeksenen.</string>
-    <string name="settings_room_directory_show_all_rooms">Keamers mei ynhâld foar folwoeksenen toane</string>
-    <string name="settings_category_room_directory">Keameroersjoch</string>
+    <string name="spaces_invited_header">Utnûge persoanen</string>
+    <string name="settings_room_directory_show_all_rooms_summary">Alle petearen yn de list toane, ek petearen mei ynhâld foar folwoeksenen.</string>
+    <string name="settings_room_directory_show_all_rooms">Petearen mei ynhâld foar folwoeksenen toane</string>
+    <string name="settings_category_room_directory">Petearlist</string>
     <string name="no_more_results">Gjin resultaten mear</string>
-    <string name="suggested_header">Oanrekommandearre Keamers</string>
+    <string name="suggested_header">Oanrekommandearre petearen</string>
     <string name="dialog_edit_hint">Nije wearde</string>
-    <string name="action_switch">Omskeakelje</string>
+    <string name="action_switch">Wikselje</string>
     <string name="action_copy">Kopiearje</string>
     <string name="cannot_call_yourself">Jo kinne josels net belje</string>
     <string name="no_permissions_to_start_conf_call_in_direct_room">Jo meie gjin konferinsje starte</string>
-    <string name="no_permissions_to_start_conf_call">Jo meie gjin konferinsjepetear yn dizze keamer starte</string>
-    <string name="start_chatting">Petearen starte</string>
-    <string name="denied_permission_camera">Om dizze aksje út te fieren, skeakelje dan de kameratastimming yn fan de systeemynstellingen út.</string>
+    <string name="no_permissions_to_start_conf_call">Jo misse it rjocht om in gearkomste yn dit petear te starten</string>
+    <string name="start_chatting">Starte mei chatten</string>
+    <string name="denied_permission_camera">Skeakelje om dizze aksje út te fieren fan de systeemynstellingen út de kameratastimming yn.</string>
     <string name="notice_end_to_end_ok_by_you">Jo hawwe end-to-end-fersifering ynskeakele.</string>
     <string name="notice_end_to_end_ok">%1$s hat end-to-end-fersifering ynskeakele.</string>
-    <string name="notice_direct_room_guest_access_forbidden">%1$s hat opkeard dat gasten dizze keamer binnen gean kinne.</string>
-    <string name="notice_room_guest_access_forbidden_by_you">Jo hawwe opkeard dat gasten dizze keamer binnen gean kinne.</string>
-    <string name="notice_room_guest_access_forbidden">%1$s hat opkeard dat gasten dizze keamer binnen gean kinne.</string>
-    <string name="notice_direct_room_guest_access_forbidden_by_you">Jo hawwe opkeard dat gasten dizze keamer binnen gean kinne.</string>
+    <string name="notice_direct_room_guest_access_forbidden">%1$s hat opkeard dat gasten dit petear binnen gean kinne.</string>
+    <string name="notice_room_guest_access_forbidden_by_you">Jo hawwe opkeard dat gasten dit petear binnen gean kinne.</string>
+    <string name="notice_room_guest_access_forbidden">%1$s hat opkeard dat gasten dit petear binnen gean kinne.</string>
+    <string name="notice_direct_room_guest_access_forbidden_by_you">Jo hawwe opkeard dat gasten dit petear binnen gean kinne.</string>
     <string name="notice_direct_room_guest_access_can_join_by_you">Jo hawwe gasten tastien om hjir binnen te gean.</string>
     <string name="notice_direct_room_guest_access_can_join">%1$s hat gasten tastien om hjir binnen te gean.</string>
     <string name="notice_room_guest_access_can_join_by_you">Jo hawwe gasten tastien om dizze keamer binnen te gean.</string>
     <string name="notice_room_guest_access_can_join">%1$s hat gasten tastien om dizze keamer binnen te gean.</string>
     <string name="system_theme">Systeemstandert</string>
-    <string name="notice_end_to_end_unknown_algorithm_by_you">Jo hawwe end-to-end-fersifering ynskeakele (net erkend algoritme %1$s).</string>
+    <string name="notice_end_to_end_unknown_algorithm_by_you">Jo hawwe end-to-end-fersifering ynskeakele (ûnbekend algoritme %1$s).</string>
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="one">%1$s en 1 oar</item>
         <item quantity="other">%1$s en %2$d oaren</item>
@@ -1005,39 +1006,39 @@
     <string name="room_displayname_4_members">%1$s, %2$s, %3$s en %4$s</string>
     <string name="room_displayname_3_members">%1$s, %2$s en %3$s</string>
     <string name="room_displayname_two_members">%1$s en %2$s</string>
-    <string name="room_displayname_room_invite">Keamerútnûging</string>
+    <string name="room_displayname_room_invite">Petearútnûging</string>
     <string name="room_error_join_failed_empty_room">It is no net mooglik om in lege keamer wer binnen te gean.</string>
-    <string name="notice_room_third_party_registered_invite_by_you">Jo hawwe de útnûging nei %1$s oannaam</string>
-    <string name="notice_room_third_party_registered_invite">%1$s hat de útnûging nei %2$s oannaam</string>
-    <string name="notice_direct_room_third_party_revoked_invite_by_you">Jo hawwe de útnûging nei %1$s ynlutsen</string>
-    <string name="notice_direct_room_third_party_revoked_invite">%1$s hat de útnûging nei %2$s wer ynlutsen</string>
+    <string name="notice_room_third_party_registered_invite_by_you">Jo hawwe de útnûging nei %1$s akseptearre</string>
+    <string name="notice_room_third_party_registered_invite">%1$s hat de útnûging oan %2$s akseptearre</string>
+    <string name="notice_direct_room_third_party_revoked_invite_by_you">Jo hawwe de útnûging oan %1$s ynlutsen</string>
+    <string name="notice_direct_room_third_party_revoked_invite">%1$s hat de útnûging oan %2$s wer ynlutsen</string>
     <string name="notice_room_third_party_revoked_invite_by_you">Jo hawwe de útnûging nei %1$s om de keamer binnen te gean wer ynlutsen</string>
     <string name="notice_room_third_party_revoked_invite">%1$s hat de útnûging nei %2$s om de keamer binnen te gean wer ynlutsen</string>
     <string name="notice_direct_room_third_party_invite_by_you">Jo hawwe %1$s útnûge</string>
     <string name="notice_direct_room_third_party_invite">%1$s hat %2$s útnûge</string>
-    <string name="notice_room_third_party_invite_by_you">Jo hawwe in útnûging nei %1$s stjoerd om de keamer binnen te gean</string>
-    <string name="notice_room_third_party_invite">%1$s hat in útnûging nei %2$s stjoerd om de keamer binnen te gean</string>
-    <string name="notice_room_avatar_removed">%1$s hat de keamerôfbylding fuortsmiten</string>
-    <string name="notice_voip_finished">VoIP-konferinsje ôfrûn</string>
+    <string name="notice_room_third_party_invite_by_you">Jo hawwe in útnûging nei %1$s stjoerd om by de keamer oan te sluten</string>
+    <string name="notice_room_third_party_invite">%1$s hat in útnûging nei %2$s stjoerd om mei it petear mei te dwaan</string>
+    <string name="notice_room_avatar_removed">%1$s hat de keameravatar fuortsmiten</string>
+    <string name="notice_voip_finished">VoIP-konferinsje foltôge</string>
     <string name="notice_voip_started">VoIP-konferinsje begûn</string>
     <string name="notice_requested_voip_conference_by_you">Jo hawwe in VoIP-konferinsje oanfrege</string>
     <string name="notice_requested_voip_conference">%1$s hat in VoIP-konferinsje oanfrege</string>
-    <string name="notice_room_server_acl_allow_is_empty">🎉 Alle servers bin ferballe fan it meidwaan! Dizze keamer kin net mear brûkt wurde.</string>
-    <string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Tsjinners dy oerien komme mei IP adressen binne no ferballe.</string>
-    <string name="notice_room_server_acl_updated_ip_literals_allowed">• Tsjinners dy oerien komme mei IP adressen binne no tastien.</string>
-    <string name="notice_room_server_acl_updated_was_allowed">• Tsjinners dy oerien komme mei %s binne út de list mei tastiene tsjinners wei helle.</string>
-    <string name="notice_room_server_acl_updated_allowed">• Tsjinners dy oerien komme mei %s binne no tastien.</string>
-    <string name="notice_room_server_acl_updated_was_banned">• Tsjinners dy oerien komme mei %s binne út de list mei ferballe tsjinners wei helle.</string>
-    <string name="notice_room_server_acl_updated_banned">• Tsjinners dy oerien komme mei %s binne no ferballe.</string>
-    <string name="notice_room_server_acl_set_ip_literals_not_allowed">• Tsjinners dy oerien komme mei IP adressen binne ferballe.</string>
-    <string name="notice_room_server_acl_set_ip_literals_allowed">• Tsjinners dy oerien komme mei IP adressen binne tastien.</string>
-    <string name="notice_room_server_acl_set_banned">• Tsjinners dy oerien komme mei %s binne ferballe.</string>
-    <string name="notice_room_avatar_removed_by_you">Jo hawwe de keamerôfbylding fuortsmiten</string>
-    <string name="notice_room_avatar_changed_by_you">Jo hawwe de keamer ôfbylding feroare</string>
-    <string name="notice_room_avatar_changed">%1$s hat de keamer ôfbylding feroare</string>
-    <string name="notice_avatar_url_changed">%1$s hat syn profylfoto feroare</string>
-    <string name="notice_room_withdraw_with_reason_by_you">Jo hawwe %1$s harren útnûging ynlutsen. Reden: %2$s</string>
-    <string name="notice_room_withdraw_with_reason">%1$s hat %2$s harren útnûging ynlutsen. Reden: %3$s</string>
+    <string name="notice_room_server_acl_allow_is_empty">🎉 Alle servers binne ferballe fan dielname! Dizze keamer kin net mear brûkt wurde.</string>
+    <string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Servers dy’t oerienkomme mei IP-adressen binne no ferballe.</string>
+    <string name="notice_room_server_acl_updated_ip_literals_allowed">• Servers dy’t oerienkomme mei IP-adressen binne no tastien.</string>
+    <string name="notice_room_server_acl_updated_was_allowed">• Servers dy’t oerienkomme mei %s binne út de list mei tastiene servers fuorthelle.</string>
+    <string name="notice_room_server_acl_updated_allowed">• Servers dy’t oerienkomme mei %s binne no tastien.</string>
+    <string name="notice_room_server_acl_updated_was_banned">• Servers dy’t oerienkomme mei %s binne út de list mei ferballe servers fuorthelle.</string>
+    <string name="notice_room_server_acl_updated_banned">• Servers dy’t oerienkomme mei %s binne no ferballe.</string>
+    <string name="notice_room_server_acl_set_ip_literals_not_allowed">• Servers dy’t oerienkomme mei IP-adressen binne ferballe.</string>
+    <string name="notice_room_server_acl_set_ip_literals_allowed">• Servers dy’t oerienkomme mei IP-adressen binne tastien.</string>
+    <string name="notice_room_server_acl_set_banned">• Servers dy’t oerienkomme mei %s binne ferballe.</string>
+    <string name="notice_room_avatar_removed_by_you">Jo hawwe de keameravatar fuortsmiten</string>
+    <string name="notice_room_avatar_changed_by_you">Jo hawwe de keamerôfbylding wizige</string>
+    <string name="notice_room_avatar_changed">%1$s hat de keamerôfbylding wizige</string>
+    <string name="notice_avatar_url_changed">%1$s hat syn profylfoto wizige</string>
+    <string name="notice_room_withdraw_with_reason_by_you">Jo hawwe de útnûging fan %1$s ynlutsen. Reden: %2$s</string>
+    <string name="notice_room_withdraw_with_reason">%1$s hat de útnûging fan %2$s ynlutsen. Reden: %3$s</string>
     <string name="notice_room_third_party_registered_invite_with_reason_by_you">Jo hawwe de útnûging foar %1$s akseptearre. Reden: %2$s</string>
     <string name="notice_room_third_party_registered_invite_with_reason">%1$s hat de útnûging foar %2$s akseptearre. Reden: %3$s</string>
     <string name="notice_room_unban_by_you">Jo hawwe %1$s net mear ferballe</string>
@@ -1052,17 +1053,146 @@
     <string name="auth_add_phone_message_2">Kies in telefoannûmer. Letter kinne jo derfoar kieze om minsken jo fine te litten fia dit nûmer.</string>
     <string name="auth_add_email_message_2">Kies in e-mailadres om te brûken foar accountwerstel. Letter kinne jo derfoar kieze om minsken jo fine te litten fia jo e-mailadres.</string>
     <string name="auth_return_to_login">Tebek nei it oanmeldingsskerm</string>
-    <string name="auth_send_reset_email">E-mail foar opnij ynstellen ferstjoere</string>
+    <string name="auth_send_reset_email">E-mailberjocht foar opnij ynstellen ferstjoere</string>
     <string name="auth_submit">Yntsjinje</string>
     <string name="auth_register">Account oanmeitsje</string>
     <string name="auth_login_sso">Oanmelde mei unike oanmelding</string>
     <string name="send_files_in">Ferstjoere nei</string>
     <string name="action_unpublish">Depublisearje</string>
-    <string name="audio_meeting">Start audiopetear</string>
-    <string name="video_meeting">Start fideopetear</string>
+    <string name="audio_meeting">Audiopetear starte</string>
+    <string name="video_meeting">Fideopetear starte</string>
     <string name="missing_permissions_title">Missende tastimmingen</string>
     <string name="spaces">Romten</string>
     <string name="learn_more">Mear ynfo</string>
     <string name="reset">Opnij ynstelle</string>
     <string name="dismiss">Slute</string>
+    <string name="call_tile_in_call">Jo binne op dit stuit yn dit petear</string>
+    <string name="settings_security_pin_code_change_pin_summary">Jo aktuele pinkoade wizigje</string>
+    <string name="choose_locale_current_locale_title">Aktuele taal</string>
+    <string name="devices_current_device">Aktuele sesje</string>
+    <string name="settings_security_pin_code_notifications_summary_off">Allinnich werjeftenûmer fan oantal berjochten yn in ienfâldige notifikaasje.</string>
+    <string name="settings_security_pin_code_notifications_summary_on">Details as keamernamme en berjochtynhâld toane.</string>
+    <string name="settings_security_pin_code_notifications_title">Ynhâld yn notifikaasjes toane</string>
+    <string name="alert_push_are_disabled_description">Besjoch jo ynstellingen om pushnotifikaasjes yn te skeakeljen</string>
+    <string name="alert_push_are_disabled_title">Pushnotifikaasjes binne útskeakele</string>
+    <string name="settings_notification_configuration">Konfiguraasje notifikaasjes</string>
+    <string name="room_profile_section_more_notifications">Notifikaasjes</string>
+    <string name="room_list_quick_actions_notifications_mute">Dôvje</string>
+    <string name="room_list_quick_actions_notifications_mentions">Allinnich fermeldingen</string>
+    <string name="room_list_quick_actions_notifications_all">Alle berjochten</string>
+    <string name="room_list_quick_actions_notifications_all_noisy">Alle berjochten (drok)</string>
+    <string name="room_settings_room_notifications_account_settings">Accountynstellingen</string>
+    <string name="room_settings_room_notifications_manage_notifications">Jo kinne notifikaasjes beheare yn %1$s.</string>
+    <string name="settings_pin_missed_notifications">Petearen mei miste notifikaasjes fêstsette</string>
+    <string name="settings_notifications_targets">Notifikaasjedoelen</string>
+    <string name="settings_call_notifications_preferences">Opropnotifikaasjes konfigurearje</string>
+    <string name="settings_notification_privacy_nosecure_message_content">• Notifikaasjes befetsje <b>meta- en berjochtgegevens</b></string>
+    <string name="settings_troubleshoot_test_service_restart_title">Notifikaasjetsjinst automatysk opnij starte</string>
+    <string name="settings_troubleshoot_test_foreground_service_started_failed">Notifikaasjetsjinst is net aktyf.
+\nProbearje de app opnij te starten.</string>
+    <string name="settings_troubleshoot_test_foreground_service_startedt_success">Notifikaasjetsjinst is aktyf.</string>
+    <string name="settings_troubleshoot_test_device_settings_success">Notifikaasjes binne foar dizze sesje ynskeakele.</string>
+    <string name="settings_notification_troubleshoot">Problemen mei notifikaasjes oplosse</string>
+    <string name="settings_notification_default">Standert notifikaasjes</string>
+    <string name="soft_logout_clear_data_dialog_submit">Gegevens wiskje</string>
+    <string name="soft_logout_clear_data_dialog_title">Gegevens wiskje</string>
+    <string name="soft_logout_clear_data_submit">Alle gegevens wiskje</string>
+    <string name="soft_logout_clear_data_title">Persoanlike gegevens wiskje</string>
+    <string name="login_clear_homeserver_history">Skiednis wiskje</string>
+    <string name="command_description_clear_scalar_token">Om Matrix-appbehear te werstellen</string>
+    <string name="settings_clear_media_cache">Mediabuffer wiskje</string>
+    <string name="settings_clear_cache">Buffer wiskje</string>
+    <string name="room_manage_integrations">Yntegraasjes beheare</string>
+    <string name="settings_integrations">Yntegraasjes</string>
+    <string name="settings_discovery_emails_title">Te finen e-mailadressen</string>
+    <string name="settings_notification_emails_enable_for_email">E-mailnotifikaasjes ynskeakelje foar %s</string>
+    <string name="settings_notification_emails_no_emails">Foegje in e-mailadres ta oan jo Matrix-account, om e-mailnotifikaasjes te ûntfangen</string>
+    <string name="settings_notification_emails_category">E-mailnotifikaasje</string>
+    <string name="settings_emails_empty">Der is gjin e-mailadres oan jo account tafoege</string>
+    <string name="settings_display_name">Werjeftenamme</string>
+    <string name="command_description_nick_for_room">Wiziget jo werjeftenamme allinnich yn de aktuele keamer</string>
+    <string name="command_description_nick">Wiziget jo werjeftenamme</string>
+    <string name="room_widget_permission_display_name">Jo werjeftenamme</string>
+    <string name="settings_show_avatar_display_name_changes_messages_summary">Befettet wizigingen yn avatar en werjeftenamme.</string>
+    <string name="settings_show_room_member_state_events_summary">Befettet útnûging/meidwaan/ferlitten/skopt/ferballe-barrens en wizigingen avatar/werjeftenamme.</string>
+    <string name="template_settings_background_fdroid_sync_mode_real_time_description">${app_name} sil periodyk op de eftergrûn syngronisearje (konfigurearber).
+\nDit hat in negative ynfloed op jo batterij- en datagebrûk. Der sil in melding toand wurde ta ynformaasje.</string>
+    <string name="settings_messages_containing_display_name">Myn werjeftenamme</string>
+    <string name="settings_containing_my_display_name">Berjochten dy’t myn werjeftenamme befetsje</string>
+    <string name="template_invite_friends_rich_title">🔐️ Doch mei my mei op ${app_name}</string>
+    <string name="template_invite_friends_text">Ah goeie, praat mei my op ${app_name}: %s</string>
+    <string name="invite_friends">Freonen útnûgje</string>
+    <string name="room_settings_de_prioritize">Lege prioriteit</string>
+    <string name="room_settings_favourite">Favoryt</string>
+    <string name="room_settings_none">Gjin</string>
+    <string name="room_settings_mute">Dôvje</string>
+    <string name="room_settings_mention_only">Allinnich fermeldingen</string>
+    <string name="space_settings_permissions_title">Spacerjochten</string>
+    <string name="invite_no_identity_server_error">Foegje in identiteitsserver ta yn de ynstellingen om dit te dwaan.</string>
+    <string name="settings_call_category">Oproppen</string>
+    <string name="notice_room_canonical_alias_unset">%1$s hat it haadadres foar dit petear fuortsmiten.</string>
+    <string name="notice_room_canonical_alias_set_by_you">Jo hawwe it haadadres foar dit petear ynsteld op %1$s.</string>
+    <string name="notice_room_canonical_alias_set">%1$s hat it haadadres foar dit petear ynsteld op %2$s.</string>
+    <string name="notice_room_aliases_added_and_removed_by_you">Jo hawwe %1$s as petearadres tafoege en %2$s fuortsmiten.</string>
+    <string name="notice_room_aliases_added_and_removed">%1$s hat %2$s as petearadres tafoege en %3$s fuortsmiten.</string>
+    <plurals name="notice_room_aliases_removed_by_you">
+        <item quantity="one">Jo hawwe %1$s as petearadres fuortsmiten.</item>
+        <item quantity="other">Jo hawwe %1$s as petearadresens fuortsmiten.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_removed">
+        <item quantity="one">%1$s hat %2$s as petearadres fuortsmiten.</item>
+        <item quantity="other">%1$s hat %2$s as petearadressen fuortsmiten.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_added_by_you">
+        <item quantity="one">Jo hawwe %1$s as petearadres tafoege.</item>
+        <item quantity="other">Jo hawwe %1$s as petearadressen tafoege.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_added">
+        <item quantity="one">%1$s hat %2$s as petearadres tafoege.</item>
+        <item quantity="other">%1$s hat %2$s as petearadressen tafoege.</item>
+    </plurals>
+    <string name="notice_room_third_party_revoked_invite_with_reason_by_you">Jo hawwe de útnûging foar %1$s ynlutsen. Reden: %2$s</string>
+    <string name="notice_room_third_party_revoked_invite_with_reason">%1$s hat de útnûging foar %2$s ynlutsen. Reden: %3$s</string>
+    <string name="notice_room_third_party_invite_with_reason_by_you">Jo hawwe %1$s in útnûging foar it petear stjoerd. Reden: %2$s</string>
+    <string name="notice_room_third_party_invite_with_reason">%1$s hat %2$s in útnûging stjoerd foar in petear. Reden: %3$s</string>
+    <string name="notice_room_ban_with_reason_by_you">Jo hawwe %1$s ferballe. Reden: %2$s</string>
+    <string name="notice_room_ban_with_reason">%1$s hat %2$s ferballe. Reden: %3$s</string>
+    <string name="notice_room_unban_with_reason_by_you">Jo hawwe de ferballing fan %1$s opheven. Reden: %2$s</string>
+    <string name="notice_room_unban_with_reason">%1$s hat %2$s ûnferballe. Reden: %3$s</string>
+    <string name="notice_room_reject_with_reason_by_you">Jo hawwe de útnûging wegere. Reden: %1$s</string>
+    <string name="notice_room_reject_with_reason">%1$s hat de útnûging wegere. Reden: %2$s</string>
+    <string name="initial_sync_start_importing_account_crypto">Inisjele syngronisaasje:
+\nKryptografy ymportearje</string>
+    <string name="notice_crypto_error_unkwown_inbound_session_id">It apparaat fan de ôfstjoerder hat gjin kaaien foar dit berjocht stjoerd.</string>
+    <string name="notice_power_level_diff">%1$s fan %2$s nei %3$s</string>
+    <string name="notice_power_level_changed">%1$s hat it machtigingsnivo fan %2$s oanpast.</string>
+    <string name="notice_power_level_changed_by_you">Jo hawwe it machtigingsnivo fan %1$s oanpast.</string>
+    <string name="power_level_moderator">Moderator</string>
+    <string name="notice_widget_jitsi_modified">Fideokonferinsje oanpast troch %1$s</string>
+    <string name="notice_widget_jitsi_removed_by_you">Jo hawwe de fideokonferinsje beëinige</string>
+    <string name="notice_widget_jitsi_removed">Fideokonferinsje beëinige troch %1$s</string>
+    <string name="notice_widget_jitsi_added_by_you">Jo hawwe in fideokonferinsje start</string>
+    <string name="notice_widget_jitsi_added">Fideokonferinsje start troch %1$s</string>
+    <string name="notice_widget_modified_by_you">Jo hawwe de widget %1$s oanpast</string>
+    <string name="notice_widget_modified">%1$s hat de widget %2$s oanpast</string>
+    <string name="notice_widget_removed_by_you">Jo hawwe de widget %1$s fuortsmiten</string>
+    <string name="notice_widget_removed">%1$s hat de widget %2$s fuortsmiten</string>
+    <string name="notice_widget_added_by_you">Jo hawwe de widget %1$s tafoege</string>
+    <string name="notice_widget_added">%1$s hat de widget %2$s tafoege</string>
+    <string name="notice_profile_change_redacted_by_you">Jo hawwe jo profyl %1$s bywurke</string>
+    <string name="notice_profile_change_redacted">%1$s hat syn/har profyl %2$s bywurke</string>
+    <string name="notice_avatar_changed_too">(avatar is ek wizige)</string>
+    <string name="identity_server_consent_dialog_neutral_policy">Belied</string>
+    <string name="settings_discovery_no_policy_provided">Gjin belied troch de identiteitsserver opjûn</string>
+    <string name="settings_discovery_hide_identity_server_policy_title">Identiteitsserverbelied ferstopje</string>
+    <string name="settings_discovery_show_identity_server_policy_title">Identiteitsserverbelied toane</string>
+    <string name="settings_privacy_policy">Privacybelied</string>
+    <string name="room_sliding_menu_privacy_policy">Privacybelied</string>
+    <string name="create_spaces_default_public_random_room_name">Samar wat</string>
+    <string name="template_login_default_session_public_name">${app_name} Android</string>
+    <string name="encryption_information_name">Iepenbiere namme</string>
+    <string name="device_name_warning">De iepenbiere namme fan in sesje is sichtber foar minsken mei wa’t jo kommunisearje</string>
+    <string name="encryption_information_device_name_with_warning">Iepenbiere namme (sichtber foar minsken mei wa’t jo kommunisearje)</string>
+    <string name="encryption_information_device_name">Iepenbiere namme</string>
+    <string name="conference_call_in_progress">Der is al in gearkomst oan de gong!</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-hu/strings.xml b/vector/src/main/res/values-hu/strings.xml
index 3d5dfe5a67..ab80091bcc 100644
--- a/vector/src/main/res/values-hu/strings.xml
+++ b/vector/src/main/res/values-hu/strings.xml
@@ -68,7 +68,8 @@
     <string name="initial_sync_start_importing_account_rooms">Induló szinkronizáció:
 \nSzobák betöltése</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Induló szinkronizáció:
-\nCsatlakozott szobák betöltése</string>
+\nBeszélgetések betöltése
+\nHa sok szobában vagy jelen sokáig tarthat</string>
     <string name="initial_sync_start_importing_account_invited_rooms">Induló szinkronizáció:
 \nMeghívott szobák betöltése</string>
     <string name="initial_sync_start_importing_account_left_rooms">Induló szinkronizáció:
@@ -3010,4 +3011,7 @@ Ha nem te állítottad be a visszaállítási metódust, akkor egy támadó pró
     <string name="a11y_presence_unavailable">Elérhetetlen</string>
     <string name="a11y_presence_offline">Kapcsolat nélkül</string>
     <string name="a11y_presence_online">Kapcsolódva</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Matrix szerver kiválasztása</string>
+    <string name="login_error_homeserver_from_url_not_found">A matrix szervert nem sikerül elérni ezen az URL-en: %s. Ellenőrizd a kapcsolatodat vagy add meg a matrix szervert kézzel.</string>
+    <string name="notification_listening_for_notifications">Értesítések figyelése</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-in/strings.xml b/vector/src/main/res/values-in/strings.xml
index bd9098ac7b..9b77f36657 100644
--- a/vector/src/main/res/values-in/strings.xml
+++ b/vector/src/main/res/values-in/strings.xml
@@ -334,7 +334,7 @@ Ijinkan akses lewat halaman selanjutnya untuk menemukan pengguna ${app_name} yan
     <string name="room_participants_action_leave">Tinggalkan ruang ini</string>
     <string name="room_participants_action_remove">Keluarkan dari ruang ini</string>
     <string name="room_participants_action_ban">Larang</string>
-    <string name="room_participants_action_unban">Hapus Larangan</string>
+    <string name="room_participants_action_unban">Hapus Cekalan</string>
     <string name="room_participants_action_set_default_power_level">Setel ulang ke user biasa</string>
     <string name="room_participants_action_set_moderator">Jadikan moderator</string>
     <string name="room_participants_action_set_admin">Jadikan admin</string>
@@ -403,7 +403,7 @@ Ijinkan akses lewat halaman selanjutnya untuk menemukan pengguna ${app_name} yan
     <string name="room_event_action_report_prompt_reason">Alasan laporan konten ini</string>
     <string name="room_event_action_report_prompt_ignore_user">Apa Anda ingin menyembunyikan seluruh pesan dari pengguna ini\?
 \n
-\nHarap diperhatikan bahwa tindakan ini akan me-restart aplikasi dan mungkin akan memakan waktu beberapa saat.</string>
+\nHarap diperhatikan bahwa tindakan ini akan memulai ulang aplikasi dan mungkin akan membutuhkan waktu beberapa saat.</string>
     <string name="room_event_action_cancel_upload">Batalkan Unggahan</string>
     <string name="room_event_action_cancel_download">Batalkan Unduhan</string>
     <string name="search_hint">Cari</string>
@@ -522,7 +522,7 @@ Ijinkan akses lewat halaman selanjutnya untuk menemukan pengguna ${app_name} yan
     <string name="unrecognized_command">Perintah tak dikenal: %s</string>
     <string name="command_description_emote">Tunjukkan tindakan</string>
     <string name="command_description_ban_user">Larang user dengan id berikut</string>
-    <string name="command_description_unban_user">Cabut larangan pengguna dengan id berikut</string>
+    <string name="command_description_unban_user">Menghapus cekalan pengguna dengan id berikut</string>
     <string name="command_description_op_user">Tentukan tingkat kuasa seorang pengguna</string>
     <string name="command_description_invite_user">Undang pengguna dengan id berikut bergabung ke ruang ini</string>
     <string name="command_description_join_room">Gabung ke ruangan dengan alamat berikut</string>
@@ -764,7 +764,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="settings_password_updated">Kata sandi Anda telah diperbaharui</string>
     <string name="settings_unignore_user">Tunjukkan semua pesan dari %s\?
 \n
-\nMohon perhatikan bahwa tindakan ini akan me-restart aplikasi dan mungkin akan memakan waktu.</string>
+\nMohon perhatikan bahwa tindakan ini akan me-restart aplikasi dan mungkin akan membutuhkan waktu.</string>
     <string name="settings_delete_notification_targets_confirmation">Apa benar Anda ingin menyingkirkan sasaran pemberitahuan ini?</string>
     <string name="settings_delete_threepid_confirmation">Apa benar Anda ingin menyingkirkan %1$s %2$s?</string>
     <string name="settings_select_country">Pilih negara</string>
@@ -1237,26 +1237,27 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="clear_timeline_send_queue">Bersihkan antrian kiriman</string>
     <string name="event_status_sending_message">Mengirim pesan…</string>
     <string name="event_status_sent_message">Pesan terkirim</string>
-    <string name="initial_sync_start_importing_account_data">Sinkronisasi Awal:
-\nMengimpor Data Akun</string>
-    <string name="initial_sync_start_importing_account_groups">Sinkronisasi Awal:
-\nMengimpor Komunitas</string>
+    <string name="initial_sync_start_importing_account_data">Sinkronisasi awal:
+\nMengimpor data akun</string>
+    <string name="initial_sync_start_importing_account_groups">Sinkronisasi awal:
+\nMengimpor komunitas</string>
     <string name="initial_sync_start_importing_account_left_rooms">Sinkronisasi Awal:
-\nMengimpor Ruangan yang Ditinggalkan</string>
-    <string name="initial_sync_start_importing_account_invited_rooms">Sinkronisasi Awal:
-\nMengimpor Ruangan yang Diundang</string>
-    <string name="initial_sync_start_importing_account_joined_rooms">Sinkronisasi Awal:
-\nMengimpor Ruangan Tergabung</string>
-    <string name="initial_sync_start_importing_account_rooms">Sinkronisasi Awal:
-\nMengimpor Ruangan</string>
+\nMengimpor ruangan yang ditinggalkan</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Sinkronisasi awal:
+\nMengimpor ruangan yang diundang</string>
+    <string name="initial_sync_start_importing_account_joined_rooms">Sinkronisasi awal:
+\nMemuat obrolan Anda
+\nJika Anda telah bergabung dengan banyak ruangan, ini mungkin membutuhkan waktu yang cukup lama</string>
+    <string name="initial_sync_start_importing_account_rooms">Sinkronisasi awal:
+\nMengimpor ruangan</string>
     <string name="initial_sync_start_importing_account_crypto">Sinkronisasi awal:
-\nMengimpor crypto</string>
+\nMengimpor kripto</string>
     <string name="notice_power_level_changed">%1$s mengubah tingkat daya %2$s.</string>
-    <string name="initial_sync_start_importing_account">Sinkronisasi Awal:
+    <string name="initial_sync_start_importing_account">Sinkronisasi awal:
 \nMengimpor akun…</string>
-    <string name="initial_sync_start_downloading">Sinkronisasi Awal:
+    <string name="initial_sync_start_downloading">Sinkronisasi awal:
 \nMengunduh data…</string>
-    <string name="initial_sync_start_server_computing">Sinkronisasi Awal:
+    <string name="initial_sync_start_server_computing">Sinkronisasi awal:
 \nMenunggu respons server…</string>
     <string name="room_displayname_empty_room_was">Ruangan kosong (tadi adalah %s)</string>
     <plurals name="room_displayname_four_and_more_members">
@@ -1331,7 +1332,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="notice_room_server_acl_updated_ip_literals_allowed">• Server yang cocok dengan IP literal sekarang diizinkan.</string>
     <string name="notice_room_server_acl_updated_was_allowed">• Server yang cocok dengan %s telah dihapus dari daftar izin.</string>
     <string name="notice_room_server_acl_updated_allowed">• Server yang cocok dengan %s sekarang telah diizinkan.</string>
-    <string name="notice_room_server_acl_updated_was_banned">• Server yang cocok dengan %s dihapus dari daftar larangan.</string>
+    <string name="notice_room_server_acl_updated_was_banned">• Server yang cocok dengan %s dihapus dari daftar cekalan.</string>
     <string name="notice_room_server_acl_updated_title_by_you">Anda mengubah ACL server untuk ruangan ini.</string>
     <string name="notice_room_server_acl_updated_title">%s mengubah ACL server untuk ruangan ini.</string>
     <string name="notice_room_server_acl_set_ip_literals_allowed">• Server yang cocok dengan IP literal diizinkan.</string>
@@ -1872,7 +1873,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     </plurals>
     <string name="keys_backup_info_keys_all_backup_up">Semua kunci tercadangkan</string>
     <string name="secure_backup_setup">Siapkan Cadangan Aman</string>
-    <string name="keys_backup_banner_in_progress">Mencadangkan kunci Anda. Ini mungkin memakan beberapa menit…</string>
+    <string name="keys_backup_banner_in_progress">Mencadangkan kunci Anda. Ini mungkin membutuhkan beberapa menit…</string>
     <string name="keys_backup_banner_update_line2">Kelola di Cadangan Kunci</string>
     <string name="keys_backup_banner_update_line1">Kunci pesan aman baru</string>
     <string name="new_recovery_method_popup_title">Cadangan Kunci Baru</string>
@@ -1929,11 +1930,11 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="keys_backup_restore_is_getting_backup_version">Mengambil versi cadangan…</string>
     <string name="keys_backup_setup_skip_msg">Anda mungkin kehilangan akses ke pesan Anda jika Anda keluar atau kehilangan perangkat ini.</string>
     <string name="keys_backup_setup_skip_title">Yakin\?</string>
-    <string name="keys_backup_setup_backup_started_message">Kunci enkripsi Anda sekarang sedang dicadangkan di latar belakang ke homeserver Anda. Pencadangan awal dapat memakan waktu beberapa menit.</string>
+    <string name="keys_backup_setup_backup_started_message">Kunci enkripsi Anda sekarang sedang dicadangkan di latar belakang ke homeserver Anda. Pencadangan awal dapat membutuhkan waktu beberapa menit.</string>
     <string name="keys_backup_setup_backup_started_title">Pencadangan Dimulai</string>
     <string name="unexpected_error">Kesalahan tidak terduga</string>
     <string name="recovery_key">Kunci Pemulihan</string>
-    <string name="keys_backup_setup_step3_generating_key_status">Membuat Kunci Pemulihan menggunakan frasa sandi, proses ini bisa memakan beberapa detik.</string>
+    <string name="keys_backup_setup_step3_generating_key_status">Membuat Kunci Pemulihan menggunakan frasa sandi, proses ini bisa membutuhkan beberapa detik.</string>
     <string name="keys_backup_setup_step3_share_intent_chooser_title">Bagikan kunci pemulihan ke…</string>
     <string name="keys_backup_setup_step3_please_make_copy">Mohon membuat salinan</string>
     <string name="keys_backup_setup_override_stop">Berhenti</string>
@@ -2354,7 +2355,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="upgrade_public_room">Tingkatkan ruangan publik</string>
     <string name="upgrade_required">Peningkatan dibutuhkan</string>
     <string name="upgrade">Tingkatkan</string>
-    <string name="it_may_take_some_time">Mohon sabar, ini mungkin memakan waktu yang lama.</string>
+    <string name="it_may_take_some_time">Mohon sabar, ini mungkin membutuhkan waktu yang lama.</string>
     <string name="joining_replacement_room">Bergabung ke ruangan yang diganti</string>
     <string name="teammate_spaces_might_not_join">Saat ini orang-orang mungkin tidak dapat bergabung ke ruangan privat yang Anda buat.
 \n
@@ -2571,7 +2572,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="crypto_error_withheld_blacklisted">Anda tidak dapat mengakses pesan ini karena Anda telah diblokir oleh pengirim</string>
     <string name="notice_crypto_unable_to_decrypt_friendly_desc">Karena enkripsi ujung-ke-ujung, Anda mungkin harus menunggu untuk pesan dari seseorang untuk datang karena kunci enkripsinya tidak dikirim secara benar ke Anda.</string>
     <string name="crypto_utd">Tidak Dapat Mendekripsi</string>
-    <string name="notice_crypto_unable_to_decrypt_friendly">Menunggu untuk pesan ini, mungkin memakan beberapa waktu</string>
+    <string name="notice_crypto_unable_to_decrypt_friendly">Menunggu untuk pesan ini, mungkin membutuhkan beberapa waktu</string>
     <string name="notice_crypto_unable_to_decrypt_final">Anda tidak dapat mengakses pesan ini</string>
     <string name="room_settings_set_avatar">Atur avatar</string>
     <string name="room_settings_save_success">Anda berhasil mengubah pengaturan ruangan</string>
@@ -2628,8 +2629,8 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="not_a_valid_qr_code">Bukan kode QR Matrix yang valid</string>
     <string name="invitations_sent_to_two_users">Undangan terkirim ke %1$s dan %2$s</string>
     <string name="invitation_sent_to_one_user">Undangan terkirim ke %1$s</string>
-    <string name="template_invite_friends_rich_title">🔐️ Bergabung dengan saya di ${app_name]</string>
-    <string name="template_invite_friends_text">Hi, bicara dengan saya di ${app_name}: %s</string>
+    <string name="template_invite_friends_rich_title">🔐️ Bergabung dengan saya di ${app_name}</string>
+    <string name="template_invite_friends_text">Halo, bicara dengan saya di ${app_name}: %s</string>
     <string name="invite_friends">Undang teman</string>
     <string name="invite_users_to_room_title">Undang Pengguna</string>
     <string name="inviting_users_to_room">Mengundang pengguna…</string>
@@ -2767,7 +2768,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="bootstrap_finish_title">Anda telah selesai!</string>
     <string name="your_recovery_key">Kunci pemulihan Anda</string>
     <string name="bootstrap_loading_title">Mengatur pemulihan.</string>
-    <string name="bootstrap_loading_text">Ini mungkin memakan beberapa detik, mohon sabar.</string>
+    <string name="bootstrap_loading_text">Ini mungkin membutuhkan beberapa detik, mohon sabar.</string>
     <string name="bootstrap_info_text_2">Masukkan frasa keamanan yang Anda tahu, digunakan untuk mengamankan rahasia di server Anda.</string>
     <string name="bootstrap_dont_reuse_pwd">Jangan menggunakan kata sandi Akun Anda.</string>
     <string name="bootstrap_info_confirm_text">Masukkan %s Anda lagi untuk mengkonfirmasinya.</string>
@@ -2953,4 +2954,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
     <string name="a11y_presence_unavailable">Tidak Tersedia</string>
     <string name="a11y_presence_offline">Offline</string>
     <string name="a11y_presence_online">Online</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Pilih homeserver</string>
+    <string name="login_error_homeserver_from_url_not_found">Tidak dapat menjangkau homeserver di URL %s. Silakan periksa tautan Anda atau pilih sebuah homeserver secara manual.</string>
+    <string name="notification_listening_for_notifications">Mendengarkan notifikasi</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-it/strings.xml b/vector/src/main/res/values-it/strings.xml
index 7fffde72be..aef89aa189 100644
--- a/vector/src/main/res/values-it/strings.xml
+++ b/vector/src/main/res/values-it/strings.xml
@@ -69,13 +69,14 @@
     <string name="initial_sync_start_importing_account_rooms">Sincronizzazione iniziale:
 \nImportazione stanze</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Sincronizzazione iniziale:
-\nImportazione stanze partecipate</string>
+\nCaricamento delle conversazioni
+\nSe sei dentro a molte stanze, potrebbe volerci un po\'</string>
     <string name="initial_sync_start_importing_account_invited_rooms">Sincronizzazione iniziale:
 \nImportazione stanze con invito</string>
     <string name="initial_sync_start_importing_account_left_rooms">Sincronizzazione iniziale:
-\nImportazione stanze lasciate</string>
+\nImportazione stanze abbandonate</string>
     <string name="initial_sync_start_importing_account_groups">Sincronizzazione iniziale:
-\nImportazione comunità</string>
+\nImportazione delle comunità</string>
     <string name="initial_sync_start_importing_account_data">Sincronizzazione iniziale:
 \nImportazione dati account</string>
     <string name="notice_room_update">%s ha aggiornato questa stanza.</string>
@@ -1071,7 +1072,7 @@
     <string name="command_description_op_user">Imposta i poteri di un utente</string>
     <string name="command_description_deop_user">Rimuove il rango di operatore dall\'utente con l\'ID specificato</string>
     <string name="command_description_invite_user">Invita l\'utente con l\'ID specificato nella stanza corrente</string>
-    <string name="command_description_join_room">Entra nella stanza con un determinato nome</string>
+    <string name="command_description_join_room">Entra nella stanza con l\'indirizzo scelto</string>
     <string name="command_description_part_room">Esci dalla stanza</string>
     <string name="command_description_topic">Imposta l\'argomento della stanza</string>
     <string name="command_description_kick_user">Butta fuori l\'utente con l\'ID specificato</string>
@@ -3058,4 +3059,7 @@
     <string name="a11y_presence_unavailable">Non disponibile</string>
     <string name="a11y_presence_offline">Offline</string>
     <string name="a11y_presence_online">Online</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Scegli homeserver</string>
+    <string name="login_error_homeserver_from_url_not_found">Impossibile raggiungere un homeserver all\'URL %s. Controlla il link o scegli manualmente un homeserver.</string>
+    <string name="notification_listening_for_notifications">Ascolto di notifiche</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-ko/strings.xml b/vector/src/main/res/values-ko/strings.xml
index 3adf75e722..f691609567 100644
--- a/vector/src/main/res/values-ko/strings.xml
+++ b/vector/src/main/res/values-ko/strings.xml
@@ -162,13 +162,13 @@
     <string name="start_voice_call">음성 통화 시작하기</string>
     <string name="start_video_call">영상 통화 시작하기</string>
     <string name="start_new_chat_prompt_msg">정말로 %s님과 새 대화를 시작하시겠습니까\?</string>
-    <string name="start_voice_call_prompt_msg">정말 음성통화를 시작하시겠어요?</string>
-    <string name="start_video_call_prompt_msg">정말 영상통화를 시작하시겠어요?</string>
+    <string name="start_voice_call_prompt_msg">정말 음성통화를 시작하시겠습니까\?</string>
+    <string name="start_video_call_prompt_msg">정말 영상통화를 시작하시겠습니까\?</string>
     <string name="option_send_files">파일 보내기</string>
     <string name="option_send_sticker">스티커 보내기</string>
-    <string name="option_take_photo_video">사진이나 영상 찍기</string>
-    <string name="option_take_photo">사진 찍기</string>
-    <string name="option_take_video">영상 찍기</string>
+    <string name="option_take_photo_video">사진이나 영상 촬영</string>
+    <string name="option_take_photo">사진 촬영</string>
+    <string name="option_take_video">영상 촬영</string>
     <string name="auth_login">로그인</string>
     <string name="auth_register">계정 만들기</string>
     <string name="auth_submit">제출하기</string>
@@ -193,7 +193,7 @@
     <string name="stay">머물기</string>
     <string name="skip">넘기기</string>
     <string name="done">완료</string>
-    <string name="action_sign_out_confirmation_simple">정말 로그아웃하시겠어요\?</string>
+    <string name="action_sign_out_confirmation_simple">정말 로그아웃하시겠습니까\?</string>
     <string name="action_mark_room_read">읽음으로 표시</string>
     <string name="template_no_contact_access_placeholder">${app_name}이 연락처에 접근할 수 없게 되어 있습니다</string>
     <plurals name="public_room_nb_users">
@@ -246,7 +246,7 @@
     <string name="call_anyway">무시하고 통화</string>
     <string name="accept">수락하기</string>
     <string name="abort">중단</string>
-    <string name="ignore">무시</string>
+    <string name="ignore">차단</string>
     <string name="action_global_search">세계 검색</string>
     <string name="home_filter_placeholder_favorites">즐겨찾기 필터</string>
     <string name="home_filter_placeholder_people">사람 필터</string>
@@ -348,7 +348,7 @@
     <string name="call_error_ice_failed">미디어 연결 실패</string>
     <string name="call_error_camera_init_failed">카메라를 초기화할 수 없습니다</string>
     <string name="call_error_answered_elsewhere">다른 곳에서 전화 응답</string>
-    <string name="media_picker_both_capture_title">사진이나 영상 찍기</string>
+    <string name="media_picker_both_capture_title">사진이나 영상 촬영</string>
     <string name="media_picker_cannot_record_video">영상을 촬영할 수 없음</string>
     <string name="permissions_rationale_popup_title">정보</string>
     <string name="template_permissions_rationale_msg_storage">첨부 파일을 보내고 저장하려면 ${app_name}은 영상과 사진 보관함에 접근하는 권한이 필요합니다.
@@ -432,8 +432,8 @@
     <string name="room_participants_action_set_default_power_level">일반 사용자로 재 설정</string>
     <string name="room_participants_action_set_moderator">중재자로 하기</string>
     <string name="room_participants_action_set_admin">관리자로 하기</string>
-    <string name="room_participants_action_ignore">이 사용자의 모든 메시지 숨기기</string>
-    <string name="room_participants_action_unignore">이 사용자의 모든 메시지 보이기</string>
+    <string name="room_participants_action_ignore">차단</string>
+    <string name="room_participants_action_unignore">차단 해제</string>
     <string name="room_participants_invite_search_another_user">사용자 ID, 이름 혹은 이메일</string>
     <string name="room_participants_action_mention">언급</string>
     <string name="room_participants_action_devices_list">기기 목록 보이기</string>
@@ -475,7 +475,7 @@
     <string name="ssl_trust">신뢰함</string>
     <string name="ssl_do_not_trust">신뢰하지 않음</string>
     <string name="ssl_logout_account">로그아웃</string>
-    <string name="ssl_remain_offline">무시하기</string>
+    <string name="ssl_remain_offline">무시</string>
     <string name="ssl_fingerprint_hash">핑거프린트 (%s):</string>
     <string name="ssl_could_not_verify">원격 서버의 ID를 확인할 수 없습니다.</string>
     <string name="ssl_cert_not_trust">이는 누군가가 당신의 트래픽을 악의적으로 가로채고 있거나, 휴대 전화가 원격 서버에서 제공한 인증서를 신뢰하지 않는 것입니다.</string>
@@ -665,7 +665,7 @@
     <string name="settings_clear_media_cache">미디어 캐시 지우기</string>
     <string name="settings_user_settings">사용자 설정</string>
     <string name="settings_notifications">알림</string>
-    <string name="settings_ignored_users">차단한 사용자</string>
+    <string name="settings_ignored_users">차단된 사용자</string>
     <string name="settings_other">기타</string>
     <string name="settings_advanced">고급</string>
     <string name="settings_cryptography">암호화</string>
@@ -747,7 +747,7 @@
     <string name="settings_fail_to_update_password">비밀번호 갱신 실패</string>
     <string name="settings_fail_to_update_password_invalid_current_password">비밀번호가 올바르지 않습니다</string>
     <string name="settings_password_updated">당신의 비밀번호가 갱신되었습니다</string>
-    <string name="settings_unignore_user">%s님의 모든 메시지를 보이겠습니까\?
+    <string name="settings_unignore_user">%s님의 모든 메시지를 표시하시겠습니까\?
 \n
 \n이 동작은 앱을 다시 시작하고 일정 시간이 걸릴 수 있습니다.</string>
     <string name="passwords_do_not_match">비밀번호가 맞지 않음</string>
@@ -1411,19 +1411,19 @@
     <string name="report_content_custom_title">이 내용 신고하기</string>
     <string name="report_content_custom_hint">이 내용을 신고하는 이유</string>
     <string name="report_content_custom_submit">신고</string>
-    <string name="block_user">사용자 출입 금지</string>
+    <string name="block_user">사용자 차단</string>
     <string name="content_reported_title">내용 신고됨</string>
     <string name="content_reported_content">이 내용을 신고했습니다.
 \n
-\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다</string>
+\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다.</string>
     <string name="content_reported_as_spam_title">스팸 문자로 신고됨</string>
     <string name="content_reported_as_spam_content">이 내용을 스팸 메일로 신고했습니다.
 \n
-\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다</string>
+\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다.</string>
     <string name="content_reported_as_inappropriate_title">부적절한 문자로 신고됨</string>
     <string name="content_reported_as_inappropriate_content">이 내용을 부적절한 문자로 신고했습니다.
 \n
-\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다</string>
+\n이 사용자의 내용을 더 이상 보고 싶지 않다면, 사용자를 차단하거나 메시지를 감출 수 있습니다.</string>
     <string name="template_permissions_rationale_msg_keys_backup_export">${app_name}은 종단간 키를 디스크에 저장하려면 권한이 필요합니다.
 \n
 \n키를 수동으로 내보내려면 다음 팝업에서 접근을 허용해주세요.</string>
@@ -1483,4 +1483,37 @@
     <string name="pause_video">일시 정지</string>
     <string name="play_video">재생</string>
     <string name="denied_permission_voice_message">음성 메시지를 보내려면 마이크 권한을 허용해주세요.</string>
+    <string name="event_redacted">삭제된 메시지</string>
+    <string name="action_copy">복사</string>
+    <string name="unignore">차단 해제</string>
+    <string name="no_ignored_users">차단한 사용자가 없습니다</string>
+    <string name="message_ignore_user">차단</string>
+    <string name="command_description_unignore_user">차단을 해제하고, 차단 해제한 사용자의 메시지를 다시 표시합니다</string>
+    <string name="command_description_ignore_user">사용자를 차단하고, 차단한 사용자의 모든 메시지를 숨깁니다</string>
+    <string name="room_participants_action_unignore_prompt_msg">차단 해제한 사용자의 모든 메시지가 표시됩니다.</string>
+    <string name="room_participants_action_unignore_title">차단 해제</string>
+    <string name="settings_category_timeline">타임라인</string>
+    <string name="timeline_unread_messages">읽지 않은 메시지</string>
+    <string name="option_always_ask">항상 묻기</string>
+    <string name="devices_current_device">현재 세션</string>
+    <plurals name="settings_active_sessions_count">
+        <item quantity="other">%d개의 활성 세션</item>
+    </plurals>
+    <string name="settings_active_sessions_signout_device">이 세션에서 로그아웃</string>
+    <string name="settings_active_sessions_manage">세션 관리</string>
+    <string name="settings_active_sessions_show_all">모든 세션 보기</string>
+    <string name="settings_active_sessions_list">활성 세션</string>
+    <string name="settings_security_application_protection_screen_title">보안 설정</string>
+    <string name="template_settings_security_pin_code_grace_period_summary_on">${app_name}을 2분 동안 사용하지 않으면 PIN을 사용하도록 설정합니다.</string>
+    <string name="settings_security_pin_code_grace_period_title">2분 후 PIN 잠금</string>
+    <string name="settings_security_pin_code_notifications_summary_on">방 이름이나 메시지 내용같은 자세한 정보를 표시합니다.</string>
+    <string name="settings_security_pin_code_notifications_title">알림에 내용 표시</string>
+    <string name="settings_security_pin_code_change_pin_summary">설정된 PIN을 변경합니다</string>
+    <string name="settings_security_pin_code_change_pin_title">PIN 변경</string>
+    <string name="settings_security_pin_code_summary">PIN을 재설정하고 싶다면 PIN 분실을 눌러 로그아웃 후 재설정을 진행할 수 있습니다.</string>
+    <string name="settings_security_pin_code_use_biometrics_summary_on">지문 인식이나 얼굴 인식과 같은 생체 인증을 활성화합니다.</string>
+    <string name="settings_security_pin_code_use_biometrics_title">생체 인증 활성화</string>
+    <string name="settings_security_pin_code_title">PIN 활성화</string>
+    <string name="settings_security_application_protection_summary">PIN이나 생체 인증으로 보안 접근을 사용합니다.</string>
+    <string name="settings_security_application_protection_title">보안 접근</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-lv/strings.xml b/vector/src/main/res/values-lv/strings.xml
index 0b72ae5873..c08a160fe0 100644
--- a/vector/src/main/res/values-lv/strings.xml
+++ b/vector/src/main/res/values-lv/strings.xml
@@ -184,7 +184,8 @@
     <string name="initial_sync_start_importing_account_invited_rooms">Sākotnējā sinhronizācija:
 \nImportē istabas, uz kurām uzaicināts</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Sākotnējā sinhronizācija:
-\nImportē istabas, kurās ieiets</string>
+\nLādē jūsu sarunas
+\nJa esat pievienojies daudzām istabām, tas var aizņemt kādu laiku.</string>
     <string name="initial_sync_start_importing_account_rooms">Sākotnējā sinhronizācija:
 \nImportē istabas</string>
     <string name="initial_sync_start_importing_account_crypto">Sākotnējā sinhronizācija:
@@ -333,7 +334,7 @@
     <string name="create_account">Reģistrēties</string>
     <string name="login">Pierakstīties</string>
     <string name="logout">Izrakstīties</string>
-    <string name="hs_url">Bāzes servera URL adrese</string>
+    <string name="hs_url">Mājasservera URL adrese</string>
     <string name="identity_url">Identitifikācijas servera URL adrese</string>
     <string name="search">Meklēt</string>
     <string name="start_new_chat">Sākt jaunu čatu</string>
@@ -398,9 +399,9 @@
     <string name="auth_threepid_warning_message">Reģistrēšanās ar epastu un tālruņa numuru vienlaicīgi pagaidām netiek atbalstīta. Ar kontu būs saistīts vienīgi tālruņa numuru.
 \n
 \nSavu epastu varat pievienot profilam iestatījumos.</string>
-    <string name="auth_recaptcha_message">Bāzes serveris vēlas pārbaudīt, vai neesat robots</string>
+    <string name="auth_recaptcha_message">Mājasservers vēlas pārbaudīt, vai neesat robots</string>
     <string name="auth_username_in_use">Šāds lietotājvārds jau ir aizņemts</string>
-    <string name="auth_home_server">Bāzes serveris:</string>
+    <string name="auth_home_server">Mājasservers:</string>
     <string name="auth_identity_server">Identitāšu serveris:</string>
     <string name="auth_reset_password_next_step_button">Esmu verificējis(usi) savu epasta adresi</string>
     <string name="auth_reset_password_message">Lai atiestatītu paroli, ievadiet epasta adresi, kura piesaistīta kontam:</string>
@@ -672,7 +673,7 @@ Lūdzu dod piekļuves atļauju nākamajā uznirstošajā logā, lai būtu iespē
     <string name="devices_delete_pswd">Parole:</string>
     <string name="devices_delete_submit_button_label">Iesniegt</string>
     <string name="settings_logged_in">Pierakstījies kā</string>
-    <string name="settings_home_server">Bāzes serveris</string>
+    <string name="settings_home_server">Mājasserveris</string>
     <string name="settings_identity_server">Identitāšu serveris</string>
     <string name="settings_user_interface">Lietotāja saskarne</string>
     <string name="settings_interface_language">Saskarnes valoda</string>
@@ -852,7 +853,7 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
     <string name="select_room_directory">Izvēlies istabu katalogu</string>
     <string name="directory_server_fail_to_retrieve_server">Serveris, iespējams, ir nepieejams vai pārslogots</string>
     <string name="directory_server_type_homeserver">Ievadi pamatserveri no kura pieprasīt tā publisko istabu sarakstu</string>
-    <string name="directory_server_placeholder">Pamatservera URL</string>
+    <string name="directory_server_placeholder">Mājasservera nosaukums</string>
     <string name="directory_server_all_rooms_on_server">Visas istabas %s serverī</string>
     <string name="directory_server_native_rooms">Visas vietējās %s istabas</string>
     <plurals name="notification_unread_notified_messages">
@@ -1669,7 +1670,7 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
     <string name="command_description_shrug">Pievieno ¯\\_(ツ)_/¯ vienkārša teksta ziņas sākumā</string>
     <string name="command_description_markdown">Iespējo/atspējo markdown</string>
     <string name="command_description_topic">Iestata istabas tematu</string>
-    <string name="command_description_join_room">Pievienojas istabai ar norādīto aliasu</string>
+    <string name="command_description_join_room">Pievienojas istabai ar norādīto adresi</string>
     <string name="command_description_unban_user">Atceļ pieejas liegumu lietotājam ar norādīto id</string>
     <string name="command_problem_with_parameters">Komandai \"%s\" nepieciešami vairāk parametri vai arī kāds no parametriem ir nepareizs.</string>
     <string name="event_status_delete_all_failed_dialog_message">Vai tiešām vēlaties dzēst visas nenosūtītas ziņas šajā istabā\?</string>
@@ -1738,7 +1739,7 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
     <string name="enter_account_password">Ievadiet savu %s, lai turpinātu.</string>
     <string name="confirm_recovery_passphrase">Apstiprināt %s</string>
     <string name="account_password">Konta parole</string>
-    <string name="verify_cancelled_notice">Verificējiet savas ierīces no iestatījumiem.</string>
+    <string name="verify_cancelled_notice">Verifikācija tika atcelta. Jūs varat uzsākt atkal.</string>
     <string name="verify_not_me_self_verification">Kāds no uzskaitītajiem var būt kompromitēts:
 \n
 \n- jūsu parole
@@ -1853,9 +1854,9 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
 \nMēģiniet restartēt aplikāciju.</string>
     <string name="settings_troubleshoot_test_foreground_service_startedt_success">Notifikāciju Pakalpojums strādā.</string>
     <string name="settings_troubleshoot_test_notification_notification_clicked">Notifikācija tika nospiesta!</string>
-    <string name="settings_troubleshoot_test_token_registration_failed">Neizdevās reģistrēt FCM žetonu serverī:
+    <string name="settings_troubleshoot_test_token_registration_failed">Neizdevās reģistrēt FCM žetonu mājasserverī:
 \n%1$s</string>
-    <string name="settings_troubleshoot_test_token_registration_success">FCM žetons veiksmīgi reģistrēts serverī.</string>
+    <string name="settings_troubleshoot_test_token_registration_success">FCM žetons veiksmīgi reģistrēts mājasserverī.</string>
     <string name="settings_troubleshoot_test_fcm_success">FCM žetons veiksmīgi saņemts:
 \n%1$s</string>
     <string name="settings_troubleshoot_test_fcm_failed">FCM žetons netika saņemts:
@@ -1945,7 +1946,7 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
     <string name="keys_backup_setup_step3_please_make_copy">Lūdzu uztaisiet kopiju</string>
     <string name="keys_backup_setup_override_stop">Stop</string>
     <string name="keys_backup_setup_override_replace">Aizvietot</string>
-    <string name="keys_backup_setup_override_backup_prompt_tile">Dublējums jau pastāv jūsu serverī</string>
+    <string name="keys_backup_setup_override_backup_prompt_tile">Dublējums jau pastāv jūsu mājasserverī</string>
     <string name="recovery_key_export_saved">Atgūšanas atslēgas tika saglabātas.</string>
     <string name="recovery_key_export_saved_as_warning">Atgūšanas atslēga ir saglabāta \"%s\".
 \n
@@ -2108,7 +2109,7 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
     <string name="call_resume_action">Turpināt</string>
     <string name="settings_call_ringtone_dialog_title">Izvēlieties zvana signālu:</string>
     <string name="settings_call_ringtone_title">Ienākoša zvana signāls</string>
-    <string name="settings_call_ringtone_use_default_stun_sum">Izmantos %s kā rezervi, kad jūsu serveris nepiedāvā vienu (jūsu IP adrese tiks dalīta sarunas laikā)</string>
+    <string name="settings_call_ringtone_use_default_stun_sum">Izmantos %s kā rezervi, kad jūsu mājasservers nepiedāvā vienu (jūsu IP adrese tiks dalīta sarunas laikā)</string>
     <string name="settings_call_ringtone_use_default_stun">Atļaut rezerves zvanu palīdzības serveri</string>
     <string name="template_settings_call_ringtone_use_app_ringtone">Izmantot noklusējuma $ {app_name} zvana signālu ienākošajiem zvaniem</string>
     <string name="settings_call_show_confirmation_dialog_summary">Pirms zvana uzsākšanas lūgt apstiprinājumu</string>
@@ -2338,4 +2339,465 @@ Nākotnē šī pārbaudes procedūra plānota sarežģītāka.</string>
     <string name="spaces_header">Vietnes</string>
     <string name="spaces_invited_header">Uzaicinājumi</string>
     <string name="suggested_header">Ieteiktās telpas</string>
+    <string name="suggested_rooms_pills_on_empty_header">Laipni lūgti %1$s, %2$s.</string>
+    <string name="suggested_rooms_pills_on_empty_text">Jūs vēl neesat nevienā istabā. Zemāk ir dažas no ieteiktajām istabām, bet jūs varat apskatīt arī citas, izmantojot zaļo pogu apakšējā labajā pusē.</string>
+    <string name="join_anyway">Pievienoties tāpat</string>
+    <string name="join_space">Pievienoties Telpai</string>
+    <string name="create_space">Izveidot Telpu</string>
+    <string name="skip_for_now">Pagaidām izlaist</string>
+    <string name="share_space_link_message">Pievienojies manai Telpai %1$s %2$s</string>
+    <string name="invite_just_to_this_room_desc">Tie nebūs daļa no %s</string>
+    <string name="invite_just_to_this_room">Tikai uz šo istabu</string>
+    <string name="invite_to_space_with_name_desc">Viņi varēs izpētīt %s</string>
+    <string name="invite_to_space_with_name">Uzaicināt uz %s</string>
+    <string name="invite_by_link">Kopīgot saiti</string>
+    <string name="invite_by_mxid_or_mail">Ielūgt pēc lietotājvārda vai pa e-pastu</string>
+    <string name="invite_by_mxid">Ielūgt pēc lietotājvārda</string>
+    <string name="invite_by_email">Ielūgt pa e-pastu</string>
+    <string name="invite_people_to_your_space_desc">Šobrīd esi tikai tu. %s būs vēl labāk kopā ar citiem.</string>
+    <string name="invite_to_space">Uzaicināt uz %s</string>
+    <string name="invite_people_menu">Uzaicināt cilvēkus</string>
+    <string name="invite_people_to_your_space">Uzaiciniet cilvēkus uz savu Telpu</string>
+    <string name="create_space_topic_hint">Apraksts</string>
+    <string name="create_spaces_loading_message">Izveido Telpu…</string>
+    <string name="create_spaces_default_public_random_room_name">Nejaušs</string>
+    <string name="create_spaces_default_public_room_name">Vispārīgi</string>
+    <string name="create_spaces_room_private_header_desc">Izveidosim katram no tiem savu istabu. Vēlāk varat pievienot arī citas, tostarp jau esošās.</string>
+    <string name="create_spaces_room_private_header">Pie kādām lietām strādājat\?</string>
+    <string name="create_spaces_invite_public_header_desc">Nodrošiniet piekļuvi %s uzņēmumam pareizajiem cilvēkiem. Vēlāk varat uzaicināt vairāk.</string>
+    <string name="create_spaces_invite_public_header">Kas ir jūsu komandas biedri\?</string>
+    <string name="create_spaces_room_public_header_desc">Mēs izveidosim tām istabas. Vēlāk varat pievienot arī citas.</string>
+    <string name="create_spaces_room_public_header">Kādas ir dažas diskusijas, ko vēlaties apspriest %s\?</string>
+    <string name="create_space_error_empty_field_space_name">Dodiet tam nosaukumu, lai turpinātu.</string>
+    <string name="create_spaces_details_private_header">Pievienojiet sīkāku informāciju, lai palīdzētu cilvēkiem to identificēt. Tās var mainīt jebkurā brīdī.</string>
+    <string name="create_spaces_details_public_header">Pievienojiet dažas detaļas, lai tā izceltos. Tās var mainīt jebkurā brīdī.</string>
+    <string name="activity_create_space_title">Izveidot Telpu</string>
+    <string name="space_type_private_desc">Tikai uzaicinot, vislabāk priekš jums vai komandām</string>
+    <string name="space_type_public_desc">Atvērta ikvienam, vislabāk kopienām</string>
+    <string name="space_type_private">Privāta</string>
+    <string name="space_type_public">Publiska</string>
+    <string name="create_spaces_private_teammates">Privāta Telpa jums un biedriem</string>
+    <string name="create_spaces_me_and_teammates">Es un biedri</string>
+    <string name="create_spaces_make_sure_access">Pārliecinieties, ka piekļuve %s ir pareizajiem cilvēkiem. To var mainīt vēlāk.</string>
+    <string name="create_spaces_who_are_you_working_with">Ar ko jūs strādājat\?</string>
+    <string name="create_spaces_organise_rooms">Privāta telpa, kur sakārtot istabas</string>
+    <string name="create_spaces_just_me">Tikai es</string>
+    <string name="create_spaces_join_info_help">Lai pievienotos esošai Telpai, ir nepieciešams ielūgums.</string>
+    <string name="create_spaces_you_can_change_later">To var mainīt vēlāk</string>
+    <string name="create_spaces_choose_type_label">Kādu Telpu vēlaties izveidot\?</string>
+    <string name="create_spaces_type_header">Telpas ir jauns veids, kā grupēt istabas un cilvēkus</string>
+    <string name="your_private_space">Jūsu privātā Telpa</string>
+    <string name="your_public_space">Jūsu publiskā Telpa</string>
+    <string name="add_space">Pievienot Telpu</string>
+    <string name="private_space">Privāta Telpa</string>
+    <string name="public_space">Publiska Telpa</string>
+    <string name="command_description_join_space">Pievienoties Telpai ar doto ID</string>
+    <string name="command_description_add_to_space">Pievienot dotajai Telpai</string>
+    <string name="command_description_create_space">Izveidot Telpu</string>
+    <string name="dev_tools_form_hint_type">Tips</string>
+    <string name="a11y_presence_unavailable">Nav pieejams</string>
+    <string name="a11y_presence_offline">Nav tiešsaistē</string>
+    <string name="a11y_presence_online">Tiešsaistē</string>
+    <string name="a11y_public_space">Publiska Telpa</string>
+    <string name="a11y_public_room">Publiska istaba</string>
+    <string name="a11y_view_read_receipts">Skatīt kuri izlasīja</string>
+    <string name="a11y_close_emoji_picker">Aizvērt emocijzīmju izvēlni</string>
+    <string name="a11y_open_emoji_picker">Atvērt emocijzīmju izvēlni</string>
+    <string name="a11y_selected">Izvēlēts</string>
+    <string name="a11y_video">Video</string>
+    <string name="a11y_delete_avatar">Izdzēst avatāru</string>
+    <string name="a11y_change_avatar">Mainīt avatāru</string>
+    <string name="a11y_image">Bilde</string>
+    <string name="a11y_open_widget">Atvērt logrīkus</string>
+    <string name="a11y_screenshot">Ekrānšāviņš</string>
+    <string name="call_slide_to_end_conference">Velciet, lai pārtrauktu zvanu</string>
+    <string name="call_transfer_unknown_person">Nezināma persona</string>
+    <string name="call_transfer_users_tab_title">Lietotāji</string>
+    <string name="call_transfer_connect_action">Savienoties</string>
+    <string name="call_tap_to_return">%1$s Pieskarieties, lai atgrieztos</string>
+    <string name="call_one_active">Aktīvs zvans (%1$s) ·</string>
+    <plurals name="call_only_paused">
+        <item quantity="zero">Pauzētu zvanu</item>
+        <item quantity="one">Pauzēts zvans</item>
+        <item quantity="other">%1$d pauzētu zvanu</item>
+    </plurals>
+    <string name="call_only_active">Aktīvs zvans (%1$s)</string>
+    <string name="call_dial_pad_lookup_error">Tika pieļauta kļūda, meklējot tālruņa numuru</string>
+    <string name="call_dial_pad_title">Zvanu taustiņi</string>
+    <string name="call_tile_connection_failed">Savienojums neizdevās</string>
+    <string name="call_tile_no_answer">Nav atbildes</string>
+    <string name="call_tile_video_missed">Neatbildēts video zvans</string>
+    <string name="call_tile_voice_missed">Neatbildēts zvans</string>
+    <string name="call_tile_video_declined">Video zvans atteikts</string>
+    <string name="call_tile_voice_declined">Zvans atteikts</string>
+    <string name="call_tile_video_call_has_ended">Video zvans beidzās • %1$s</string>
+    <string name="call_tile_voice_call_has_ended">Balss zvans beidzās • %1$s</string>
+    <string name="call_tile_video_active">Aktīvs video zvans</string>
+    <string name="call_tile_voice_active">Aktīvs zvans</string>
+    <string name="call_tile_video_incoming">Ienākošs video zvans</string>
+    <string name="call_tile_voice_incoming">Ienākošs zvans</string>
+    <string name="call_tile_call_back">Piezvanīt atpakaļ</string>
+    <string name="call_tile_ended">Zvans beidzās</string>
+    <string name="call_tile_other_declined">%1$s atteica zvanu</string>
+    <string name="call_tile_you_declined_this_call">Jūs atteicāt šo zvanu</string>
+    <string name="call_tile_you_declined">Jūs atteicāt šim zvanam %s</string>
+    <string name="call_tile_in_call">Jūs šobrīd esat šajā zvanā</string>
+    <string name="call_tile_other_started_call">%1$s uzsāka zvanu</string>
+    <string name="call_tile_you_started_call">Jūs uzsākāt zvanu</string>
+    <string name="warning_room_not_created_yet">Telpa vēl nav izveidota. Atcelt telpas izveidi\?</string>
+    <string name="cannot_dm_self">Nevar sūtīt ziņas sev!</string>
+    <string name="auth_pin_confirm_to_disable_title">Apstipriniet PIN, lai izslēgtu PIN</string>
+    <string name="settings_security_pin_code_change_pin_summary">Nomainīt tagadējo PIN</string>
+    <string name="settings_security_pin_code_change_pin_title">Nomainīt PIN</string>
+    <string name="settings_security_pin_code_title">Ieslēgt PIN</string>
+    <string name="auth_pin_new_pin_action">Jauns PIN</string>
+    <string name="auth_pin_reset_title">Attiestatīt PIN</string>
+    <string name="auth_pin_forgot">Aizmirsāt PIN\?</string>
+    <string name="auth_pin_title">Ievadiet savu PIN</string>
+    <string name="create_pin_confirm_title">Apstipriniet PIN</string>
+    <string name="create_pin_title">Izvēlaties PIN</string>
+    <string name="crypto_utd">Nevar Atšifrēt</string>
+    <string name="room_settings_set_avatar">Iestatīt avatāru</string>
+    <string name="a11y_start_camera">Ieslēgt kameru</string>
+    <string name="a11y_stop_camera">Izslēgt kameru</string>
+    <string name="a11y_unmute_microphone">Ieslēgt mikrofonu</string>
+    <string name="a11y_mute_microphone">Izslēgt mikrofonu</string>
+    <string name="identity_server_set_alternative_notice_no_default">Varat ievadīt jebkura cita identitātes servera URL adresi.</string>
+    <string name="identity_server_set_alternative_notice">Varat arī ievadīt jebkuru citu identitātes servera URL.</string>
+    <string name="identity_server_set_default_submit">Izmantot %1$s</string>
+    <string name="identity_server_set_default_notice">Jūsu mājasserveris (%1$s) ierosina identitātes serverim izmantot %2$s</string>
+    <string name="template_identity_server_error_bulk_sha256_not_supported">Jūsu privātuma dēļ ${app_name} atbalsta tikai šifrētu lietotāja e-pasta vēstules un tālruņa numura nosūtīšanu.</string>
+    <string name="identity_server_error_terms_not_signed">Vispirms iestatījumos pieņemiet identitātes servera noteikumus.</string>
+    <string name="identity_server_error_no_identity_server_configured">Vispirms konfigurējiet identitātes serveri.</string>
+    <string name="identity_server_error_outdated_home_server">Šī darbība nav iespējama. Mājasserveris ir novecojis.</string>
+    <string name="choose_locale_loading_locales">Ielādē pieejamās valodu…</string>
+    <string name="choose_locale_other_locales_title">Citas pieejamās valodas</string>
+    <string name="choose_locale_current_locale_title">Pašreizējā valoda</string>
+    <string name="invitations_sent_to_two_users">Uzaicinājumi nosūtīti uz %1$s un %2$s</string>
+    <string name="template_invite_friends_rich_title">🔐️ Pievienojies ${app_name}</string>
+    <string name="template_invite_friends_text">Sazinieties ar mani izmantojot ${app_name}: %s</string>
+    <string name="error_empty_field_choose_password">Lūdzu, izvēlieties paroli.</string>
+    <string name="error_empty_field_choose_user_name">Lūdzu, izvēlieties lietotājvārdu.</string>
+    <string name="error_saving_media_file">Nevarēja saglabāt multivides failu</string>
+    <string name="error_adding_media_file_to_gallery">Nevarēja pievienot multivides failu galerijai</string>
+    <string name="media_file_added_to_gallery">Galerijai pievienots multivides fails</string>
+    <string name="settings_security_prevent_screenshots_title">Neatļaut ekrānšāviņus lietotnē</string>
+    <string name="use_file">Izmantot failu</string>
+    <string name="bootstrap_enter_recovery">Ievadiet savu %s, lai turpinātu</string>
+    <string name="settings_notification_advanced_summary">Paziņojuma svarīguma iestatīšana pēc notikuma</string>
+    <string name="settings_notification_configuration">Notifikāciju iestatījumi</string>
+    <string name="error_failed_to_import_keys">Neizdevās importēt atslēgas</string>
+    <string name="room_created_summary_no_topic_creation_text">%s, lai ļautu cilvēkiem uzzināt, par ko ir šī istaba.</string>
+    <string name="auth_flow_not_supported">Jūs to nevarat darīt no mobilās ierīces</string>
+    <string name="bootstrap_crosssigning_save_cloud">Nokopējiet to uz personālās mākoņa krātuves</string>
+    <string name="bootstrap_crosssigning_save_usb">Saglabājiet uz USB vai rezerves diska</string>
+    <string name="bootstrap_crosssigning_print_it">Izprintējiet un turiet to drošībā</string>
+    <string name="bootstrap_cross_signing_success">Jūsu %2$s un %1$s tagad ir iestatīti.
+\n
+\nSaglabājiet tos drošībā! Tie jums būs nepieciešami, lai atbloķētu šifrētus ziņojumus un aizsargātu informāciju, ja zaudēsiet visas aktīvās sesijas.</string>
+    <string name="keep_it_safe">Turiet to drošībā</string>
+    <string name="bootstrap_finish_title">Viss pabeigts!</string>
+    <string name="bootstrap_loading_text">Šis varētu aizņemt dažas sekundes.</string>
+    <string name="bootstrap_info_text_2">Ievadiet drošības frāzi kuru zināt tikai jūs, lai nodrošinātu noslēpumus jūsu serverī.</string>
+    <string name="bootstrap_dont_reuse_pwd">Neizmantojiet sava konta paroli.</string>
+    <string name="bootstrap_info_confirm_text">Ievadiet savu %s atkal, lai apstiprinātu.</string>
+    <string name="bootstrap_info_text">Nodrošiniet un atbloķējiet šifrētus ziņojumus ar %s.</string>
+    <string name="generate_message_key">Ģenerēt jaunu Ziņu Atslēgu</string>
+    <string name="message_key">Ziņu Atslēga</string>
+    <string name="verify_cancel_other">Jūs neverificēsiet %1$s (%2$s, ja atcelsiet tagad. Sāciet no jauna lietotāja profilā.</string>
+    <string name="verify_cancel_self_verification_from_trusted">Ja to atcelsiet, jaunajā ierīcē nevarēsiet lasīt šifrētos ziņojumus</string>
+    <string name="verify_cancel_self_verification_from_untrusted">Ja to atcelsiet, šajā ierīcē nevarēsiet lasīt šifrētus ziņojumus</string>
+    <string name="send_images_and_video_with_original_size">Nosūtīt multividi ar oriģinālo izmēru</string>
+    <plurals name="settings_active_sessions_count">
+        <item quantity="zero">%d aktīvu sesiju</item>
+        <item quantity="one">%d aktīva sesiju</item>
+        <item quantity="other">%d aktīvas sesiju</item>
+    </plurals>
+    <string name="command_description_unignore_user">Pārtrauc lietotāja ignorēšanu, rādot viņa ziņojumus</string>
+    <string name="command_description_ignore_user">Ignorē lietotāju, slēpjot viņa ziņojumus no jums</string>
+    <string name="integration_manager_not_configured">Nav konfigurēts integrācijas pārvaldnieks.</string>
+    <string name="error_jitsi_join_conf">Atvainojiet, mēģinot pievienoties konferencei, radās kļūda</string>
+    <string name="directory_add_a_new_server_error_already_added">Šis serveris jau ir iekļauts sarakstā</string>
+    <string name="directory_add_a_new_server_error">Nevar atrast šo serveri vai tā istabu sarakstu</string>
+    <string name="directory_add_a_new_server_prompt">Ievadiet jaunā servera nosaukumu, kuru vēlaties izpētīt.</string>
+    <string name="other_spaces_or_rooms_you_might_not_know">Citas Telpas vai istabas, par kurām jūs, iespējams, nezināt</string>
+    <string name="space_you_know_that_contains_this_room">Telpa, kuru zināt, kas satur šo istabu</string>
+    <string name="decide_who_can_find_and_join">Izlemiet, kurš var atrast šo istabu un pievienoties tai.</string>
+    <string name="tap_to_edit_spaces">Pieskarieties, lai rediģētu Telpas</string>
+    <string name="select_spaces">Izvēlaties Telpas</string>
+    <string name="decide_which_spaces_can_access">Izlemiet, kuras Telpas var piekļūt šai istabai. Ja Telpa ir izvēlēta, tās dalībnieki varēs atrast istabas nosaukumu un pievienoties tai.</string>
+    <string name="spaces_which_can_access">Telpas, kurām var piekļūt</string>
+    <string name="allow_space_member_to_find_and_access">Ļaujiet Telpas locekļiem atrast un piekļūt.</string>
+    <string name="room_create_member_of_space_name_can_join">Telpas %s dalībnieki var atrast, apskatīt un pievienoties.</string>
+    <string name="room_settings_room_access_restricted_description">Ikviens, kas atrodas telpā, kurā ir šī telpa, var to atrast un pievienoties tai. Tikai šīs telpas administratori var to pievienot telpai.</string>
+    <string name="room_settings_room_access_restricted_title">Telpas dalībniekiem tikai</string>
+    <string name="settings_messages_containing_display_name">Mans redzamais vārds</string>
+    <string name="room_settings_space_access_public_description">Ikviens var atrast telpu un pievienoties</string>
+    <string name="room_settings_room_access_public_description">Ikviens var atrast istabu un pievienoties</string>
+    <string name="room_settings_room_access_private_description">Tikai ielūgtās personas var atrast un pievienoties</string>
+    <string name="room_settings_room_access_private_invite_only_title">Privāts (tikai ielūgumiem)</string>
+    <string name="room_settings_room_access_entry_unknown">Nav zināmi piekļuves iestatījumi (%s)</string>
+    <string name="room_settings_room_access_entry_knock">Ikviens var pieklauvēt istabai, dalībnieki var tad pieņemt vai noraidīt</string>
+    <string name="room_alias_publish_to_directory_error">Nav iespējams iegūt pašreizējās telpas direktorija redzamību (%1$s).</string>
+    <string name="space_settings_alias_subtitle">Skatiet un pārvaldiet adreses šajā telpā.</string>
+    <string name="room_settings_access_rules_pref_dialog_title">Kurš var piekļūt\?</string>
+    <string name="room_settings_room_notifications_manage_notifications">Paziņojumus varat pārvaldīt sadaļā %1$s.</string>
+    <string name="room_settings_room_notifications_encryption_notice">Lūdzu, ņemiet vērā, ka atsauču un atslēgvārdu paziņojumi nav pieejami šifrētās istabās mobilajā ierīcē.</string>
+    <string name="command_description_nick_for_room">Maina jūsu parādīto segvārdu tikai šajā telpā.</string>
+    <string name="command_description_room_name">Iestata istabas nosaukumu</string>
+    <string name="directory_add_a_new_server">Pievienot jaunu serveri</string>
+    <string name="directory_your_server">Jūsu servers</string>
+    <string name="room_settings_room_access_public_title">Publisks</string>
+    <string name="room_settings_room_access_private_title">Privāts</string>
+    <string name="space_settings_alias_title">Telpas adrese</string>
+    <string name="room_settings_guest_access_title">Ļaut viesiem pievienoties</string>
+    <string name="room_settings_space_access_title">Telpas piekļuve</string>
+    <string name="room_settings_room_notifications_account_settings">Konta iestatījumi</string>
+    <plurals name="send_videos_with_original_size">
+        <item quantity="zero">Sūtīt video ar oriģinālo izmēru</item>
+        <item quantity="one">Sūtīt video ar oriģinālo izmēru</item>
+        <item quantity="other">Sūtīt video ar oriģinālo izmēru</item>
+    </plurals>
+    <plurals name="send_images_with_original_size">
+        <item quantity="zero">Sūtīt attēlu ar oriģinālo izmēru</item>
+        <item quantity="one">Sūtīt attēlu ar oriģinālo izmēru</item>
+        <item quantity="other">Sūtīt attēlus ar oriģinālo izmēru</item>
+    </plurals>
+    <plurals name="poll_info_final">
+        <item quantity="zero">%d balsu - Galīgie rezultāti</item>
+        <item quantity="one">%d balss - Galīgie rezultāti</item>
+        <item quantity="other">%d balsis - Galīgie rezultāti</item>
+    </plurals>
+    <plurals name="poll_info">
+        <item quantity="zero">%d balsu</item>
+        <item quantity="one">%d balss</item>
+        <item quantity="other">%d balsis</item>
+    </plurals>
+    <string name="settings_server_room_version_unstable">nestabila</string>
+    <string name="settings_server_room_version_stable">stabila</string>
+    <string name="settings_server_default_room_version">Noklusējuma versija</string>
+    <string name="settings_server_room_versions">Istabu versijas 👓</string>
+    <string name="settings_category_composer">Ziņu redaktors</string>
+    <string name="settings_category_timeline">Hronoloģija</string>
+    <string name="verify_cannot_cross_sign">Šī sesija nevar kopīgot šo verifikāciju ar citām sesijām.
+\nVerifikācija tiks saglabāta lokāli un kopīgota kādā no nākamajām lietotnes versijām.</string>
+    <string name="template_rendering_event_error_exception">${app_name} saskārās ar problēmu, atveidojot notikuma ar id \'%1$s\' saturu</string>
+    <string name="template_rendering_event_error_type_of_message_not_handled">${app_name} neapstrādā \'%1$s\' tipa ziņojumu</string>
+    <string name="template_rendering_event_error_type_of_event_not_handled">${app_name} neapstrādā \'%1$s\' tipa notikumus</string>
+    <string name="verification_scan_self_emoji_subtitle">Tā vietā pārbaudiet, salīdzinot emocijzīmes</string>
+    <string name="verification_scan_with_this_device">Noskenēt ar šo ierīci</string>
+    <string name="verification_scan_self_notice">Noskenējiet kodu ar citu ierīci vai pārslēdziet un skenējiet ar šo ierīci</string>
+    <string name="sent_a_voice_message">Balss</string>
+    <string name="verify_user_sas_emoji_security_tip">Lai nodrošinātu maksimālu drošību, izmantojiet citu uzticamu saziņas līdzekli vai pārbaudiet uz vietas.</string>
+    <string name="verify_user_sas_emoji_help_text">Apstipriniet šo lietotāju, apstiprinot, ka viņa ekrānā parādās šādas unikālas emocijzīmes tādā pašā secībā.</string>
+    <string name="login_error_threepid_denied">Jūsu e-pasta domēnu nav atļauts reģistrēt šajā serverī</string>
+    <string name="create_space_in_progress">Izveido Telpu…</string>
+    <string name="create_space_alias_hint">Telpas adrese</string>
+    <string name="command_description_lenny">Pievieno ( ͡° ͜ʖ ͡°) parasta teksta ziņai</string>
+    <string name="settings_developer_mode_show_info_on_screen_summary">Rādīt kādu noderīgu informāciju, lai palīdzētu atkļūdošanas programmā</string>
+    <string name="settings_developer_mode_show_info_on_screen_title">Parādīt atkļūdošanas informāciju ekrānā</string>
+    <string name="template_settings_developer_mode_fail_fast_summary">${app_name} var biežāk avarēt, ja rodas neparedzēta kļūda</string>
+    <string name="template_soft_logout_sso_not_same_user_error">Pašreizējā sesija ir lietotājam %1$s, un jūs sniedzat lietotāja %2$s akreditācijas datus. To neatbalsta ${app_name}.
+\nLūdzu, vispirms notīriet datus un pēc tam pierakstieties vēlreiz, izmantojot citu kontu.</string>
+    <string name="soft_logout_clear_data_dialog_content">Izdzēst visus šajā ierīcē pašlaik saglabātos datus\?
+\nPierakstieties vēlreiz, lai piekļūtu konta datiem un ziņojumiem.</string>
+    <string name="soft_logout_clear_data_notice">Brīdinājums: Šajā ierīcē joprojām tiek glabāti jūsu personas dati (tostarp šifrēšanas atslēgas).
+\n
+\nIzdzēsiet tos, ja esat beidzis lietot šo ierīci vai vēlaties pierakstīties citā kontā.</string>
+    <string name="soft_logout_signin_e2e_warning_notice">Pierakstieties, lai atgūtu šifrēšanas atslēgas, kas glabājas tikai šajā ierīcē. Jums tās ir nepieciešamas, lai lasītu visus savus drošos ziņojumus jebkurā ierīcē.</string>
+    <string name="soft_logout_signin_notice">Jūsu mājasservera (%1$s) administrators ir izslēdzis jūs no konta %2$s (%3$s).</string>
+    <string name="signed_out_notice">To var izraisīt dažādi iemesli:
+\n
+\n• Jūs esat mainījis paroli citā sesijā.
+\n
+\n• Jūs esat izdzēsis šo sesiju no citas sesijas.
+\n
+\n• Jūsu servera administrators ir anulējis jūsu piekļuvi drošības apsvērumu dēļ.</string>
+    <string name="does_not_look_like_valid_email">Neizskatās pēc derīgas e-pasta adreses</string>
+    <string name="command_description_spoiler">Nosūta doto ziņojumu kā pārsteigumu</string>
+    <string name="template_permissions_rationale_msg_keys_backup_export">${app_name} nepieciešama atļauja, lai saglabātu jūsu šifrēšanas atslēgas diskā.
+\n
+\nLūdzu, nākamajā uznirstošajā logā atļaujiet piekļuvi, lai varētu eksportēt atslēgas manuāli.</string>
+    <string name="uploads_files_subtitle">%1$s pie %2$s</string>
+    <string name="uploads_media_no_result">Šajā istabā nav multivides</string>
+    <string name="uploads_media_title">Multivide</string>
+    <string name="error_handling_incoming_share">Nevarēja apstrādāt kopīgošanas datus</string>
+    <string name="error_attachment">Iegūstot pielikumu, radās kļūda.</string>
+    <string name="error_file_too_big">Fails \'%1$s\' (%2$s) augšupielādei ir pārāk liels. Ierobežojums ir %3$s.</string>
+    <string name="error_file_too_big_simple">Fails ir pārāk liels, lai tos augšupielādētu.</string>
+    <plurals name="two_and_some_others_read">
+        <item quantity="zero">%1$s, %2$s un %3$d citi lasīja</item>
+        <item quantity="one">%1$s, %2$s un %3$d citi lasīja</item>
+        <item quantity="other">%1$s, %2$s un %3$d citi lasīja</item>
+    </plurals>
+    <string name="a11y_beta">Šī funkcija ir beta versijā</string>
+    <string name="a11y_create_direct_message_by_qr_code">Jaunas tiešās sarunas izveide, skenējot QR kodu</string>
+    <string name="a11y_create_direct_message_by_mxid">Jaunas tiešās sarunas izveide pēc Matrix ID</string>
+    <string name="a11y_create_direct_message">Izveidot jaunu tiešo sarunu</string>
+    <string name="a11y_create_menu_close">Aizveriet telpas izveides izvēlni…</string>
+    <string name="a11y_create_menu_open">Atveriet izvēlni izveidot telpu</string>
+    <string name="a11y_open_drawer">Atveriet navigācijas atvilktni</string>
+    <string name="error_network_timeout">Izskatās, ka serveris pārāk ilgi neatbild, to var izraisīt slikts savienojums vai servera kļūda. Lūdzu, pēc brīža mēģiniet vēlreiz.</string>
+    <string name="identity_server_consent_dialog_neutral_policy">Politika</string>
+    <string name="identity_server_consent_dialog_content">Vai piekrītat sūtīt savus kontaktinformācijas datus (tālruņa numurus un/vai e-pasta vēstules) uz konfigurēto identitātes serveri (%1$s), lai atklātu jums zināmus esošos kontaktus\?
+\n
+\nLai nodrošinātu lielāku konfidencialitāti, nosūtītie dati pirms nosūtīšanas tiks šifrēti.</string>
+    <string name="settings_discovery_no_policy_provided">Identitātes serveris nesniedz nekādu politiku</string>
+    <string name="settings_discovery_hide_identity_server_policy_title">Slēpt identitātes servera politiku</string>
+    <string name="settings_discovery_show_identity_server_policy_title">Parādīt identitātes servera politiku</string>
+    <string name="open_discovery_settings">Atvērt atklāšanas iestatījumus</string>
+    <string name="search_hint_room_name">Meklēt Vārdu</string>
+    <string name="user_directory_search_hint_2">Meklēt pēc vārda, ID vai pasta</string>
+    <string name="send_file_step_compressing_video">Kompresē video %d%%</string>
+    <string name="send_file_step_compressing_image">Kompresē bildi…</string>
+    <string name="give_feedback">Sniedziet atsauksmes</string>
+    <string name="feedback_failed">Atsauksmi neizdevās nosūtīt (%s)</string>
+    <string name="feedback_sent">Paldies, jūsu atsauksme ir veiksmīgi nosūtīta</string>
+    <string name="you_may_contact_me">Ja jums ir kādi papildjautājumi, varat sazināties ar mani</string>
+    <string name="send_feedback_space_info">Jūs izmantojat Telpu beta versiju. Jūsu atsauksmes palīdzēs izstrādāt nākamās versijas. Jūsu platforma un lietotājvārds tiks atzīmēti, lai mēs varētu pēc iespējas labāk izmantot jūsu atsauksmes.</string>
+    <string name="feedback">Atsauksmes</string>
+    <string name="send_feedback_space_title">Atsauksmes par Telpām</string>
+    <string name="push_gateway_item_format">Format:</string>
+    <string name="push_gateway_item_url">Url:</string>
+    <string name="push_gateway_item_device_name">session_name:</string>
+    <string name="push_gateway_item_app_display_name">app_display_name:</string>
+    <string name="push_gateway_item_push_key">push_key:</string>
+    <string name="push_gateway_item_app_id">app_id:</string>
+    <string name="settings_push_gateway_no_pushers">Nav reģistrētu Palaišanas vārtu</string>
+    <string name="settings_push_rules_no_rules">Nav iestatīti Palaišanas Noteikumi</string>
+    <string name="settings_push_rules">Palaišanas Noteikumi</string>
+    <string name="template_room_preview_world_readable_room_not_supported_yet">Lasāmo telpu priekšskatījums vēl nav atbalstīts ${app_name}</string>
+    <string name="create_new_space">Radīt jaunu Telpu</string>
+    <string name="error_user_already_logged_in">Izskatās, ka mēģināt izveidot savienojumu ar citu mājasserveri. Vai vēlaties izrakstīties\?</string>
+    <string name="identity_server_not_defined_for_password_reset">Identitātes serveris nav konfigurēts, tas ir nepieciešams, lai atiestatītu paroli.</string>
+    <string name="sas_error_m_unknown_method">Sesija nevar vienoties par atslēgas vienošanās, šifrēšanas, MAC vai SAS metodi</string>
+    <string name="sas_error_m_unknown_transaction">Sesija nezina par šo darījumu</string>
+    <string name="sas_error_m_mismatched_commitment">Šifrējums neatbilda</string>
+    <string name="sas_verification_request_notification_channel">Interaktīvā Sesijas verifikācija</string>
+    <string name="room_settings_room_notifications_notify_me">Paziņot mani priekš</string>
+    <string name="settings_mentions_and_keywords_encryption_notice">Jūs nesaņemsiet paziņojumus par pieminējumiem un atslēgvārdiem šifrētās telpās mobilajās ierīcēs.</string>
+    <string name="settings_room_upgrades">Istabu atjauninājumi</string>
+    <string name="settings_messages_by_bot">Ziņas no bota</string>
+    <string name="settings_room_invitations">Istabu ielūgumi</string>
+    <string name="settings_messages_containing_keywords">Atslēgvārdi</string>
+    <string name="settings_mentions_at_room">\@istaba</string>
+    <string name="settings_encrypted_group_messages">Šifrētās grupu ziņas</string>
+    <string name="settings_group_messages">Grupu ziņas</string>
+    <string name="settings_encrypted_direct_messages">Šifrētās tiešās ziņas</string>
+    <string name="settings_messages_direct_messages">Tiešās ziņas</string>
+    <string name="sas_verifying_keys">Nekas neparādās\? Vēl ne visi klienti atbalsta interaktīvu verifikāciju. Izmantojiet veco verifikāciju.</string>
+    <string name="settings_messages_containing_username">Mans lietotājvārds</string>
+    <string name="template_autodiscover_well_known_autofill_dialog_message">${app_name} atklāja pielāgotu servera konfigurāciju jūsu lietotāja ID domēnam \"%1$s\":
+\n%2$s</string>
+    <string name="autodiscover_well_known_autofill_dialog_title">Automātiskās servera pabeigšanas opcijas</string>
+    <string name="autodiscover_invalid_response">Nederīga mājasservera atbilde</string>
+    <string name="keys_backup_get_version_error">Neizdevās iegūt jaunāko atjaunošanas atslēgu versiju (%s).</string>
+    <plurals name="keys_backup_restore_success_description_part2">
+        <item quantity="zero">%d jaunu atslēgu tika pievienotas šai sesijai.</item>
+        <item quantity="one">%d jauna atslēgu tika pievienotas šai sesijai.</item>
+        <item quantity="other">%d jaunas atslēgu tika pievienotas šai sesijai.</item>
+    </plurals>
+    <string name="keys_backup_restore_with_passphrase_helper_with_link">Neziniet atkopšanas paroli, varat %s.</string>
+    <string name="keys_backup_restore_is_getting_backup_version">Iegūst rezerves kopiju…</string>
+    <string name="keys_backup_setup_backup_started_message">Tagad jūsu šifrēšanas atslēgas fona režīmā tiek dublētas mājasserverī. Sākotnējā dublēšana var aizņemt vairākas minūtes.</string>
+    <string name="keys_backup_setup_step3_generating_key_status">Atjaunošanas atslēgas ģenerēšana, izmantojot paroli, šis process var aizņemt vairākas sekundes.</string>
+    <string name="keys_backup_setup_override_backup_prompt_description">Izskatās, ka jums jau ir izveidots atslēgas dublējums no citas sesijas. Vai vēlaties to aizstāt ar izveidoto\?</string>
+    <string name="template_keys_backup_passphrase_not_empty_error_message">Lūdzu, dzēsiet parolesfrāzi, ja vēlaties, lai ${app_name} ģenerētu atkopšanas atslēgu.</string>
+    <string name="no_valid_google_play_services_apk">Nav atrasts derīgs Google Play Services APK. Paziņojumi var nedarboties pareizi.</string>
+    <string name="error_lazy_loading_not_supported_by_home_server">Jūsu mājasserveris vēl neatbalsta fona istabas lietotāju ielādēšanu. Izmēģiniet vēlāk.</string>
+    <string name="markdown_has_been_disabled">Marķēšana ir izslēgta.</string>
+    <string name="markdown_has_been_enabled">Marķēšana ir ieslēgta.</string>
+    <string name="command_description_whois">Parāda informāciju par lietotāju</string>
+    <string name="command_description_clear_scalar_token">Lai salabotu Matrix Apps vadību</string>
+    <string name="command_description_avatar_for_room">Nomaina jūsu avatāru tikai šajā istabā</string>
+    <string name="command_description_room_avatar">Nomaina šīs istabas avatāru</string>
+    <string name="settings_when_rooms_are_upgraded">Kad istabas ir atjaunotas</string>
+    <string name="settings_notification_privacy_message_content_not_shown">• Paziņojumos <b>nebūs redzams ziņas saturs</b></string>
+    <string name="settings_notification_privacy_secure_message_content">• Paziņojuma saturs ir <b>nosūtīts tieši no Matrix mājasservera</b></string>
+    <string name="settings_notification_privacy_no_background_sync">Lietotnēm <b>nav</b> fona režīmā jāizveido savienojums ar mājasserveri, un tas samazinātu akumulatora enerģijas patēriņu</string>
+    <string name="template_settings_troubleshoot_test_bg_restricted_failed">Fona ierobežojumi ir ieslēgti lietotnei ${app_name}.
+\nDarbs, ko lietotne mēģina veikt, tiks agresīvi ierobežots, kamēr tā atrodas fonā, un tas var ietekmēt paziņojumus.
+\n%1$s</string>
+    <string name="template_settings_troubleshoot_test_bg_restricted_success">Fona ierobežojumi ir izslēgti priekš ${app_name}. Šis tests jāveic, izmantojot mobilos datus (bez WIFI).
+\n%1$s</string>
+    <string name="settings_troubleshoot_test_push_loop_failed">Neizdevās saņemt palaišanu. Iespējams, vajag pārielādēt lietotni.</string>
+    <string name="settings_troubleshoot_test_push_loop_success">Lietotne saņem Palaišanu</string>
+    <string name="settings_troubleshoot_test_push_loop_waiting_for_push">Lietotne gaida Palaišanu</string>
+    <string name="settings_troubleshoot_test_push_loop_title">Testa Palaišana</string>
+    <string name="template_settings_troubleshoot_test_fcm_failed_account_missing">[%1$s]
+\nŠī kļūda ir ārpus ${app_name} kontroles. Tālrunī nav Google konta. Lūdzu, atveriet kontu pārvaldnieku un pievienojiet Google kontu.</string>
+    <string name="template_settings_troubleshoot_test_fcm_failed_service_not_available">[%1$s]
+\nŠī kļūda ir ārpus ${app_name} kontroles. Tā var rasties vairāku iemeslu dēļ. Iespējams, tā darbosies, ja vēlāk mēģināsiet vēlreiz, varat arī pārbaudīt, vai sistēmas iestatījumos nav ierobežota Google Play pakalpojuma datu izmantošana, vai ierīces pulkstenis ir pareizs, vai arī tā var notikt uz atsevišķām sistēmām.</string>
+    <string name="template_settings_troubleshoot_test_fcm_failed_too_many_registration">[%1$s]
+\nŠī kļūda nav kontrolējama ar ${app_name}, un saskaņā ar Google datiem šī kļūda norāda, ka ierīcē ir pārāk daudz lietotņu, kas reģistrētas FCM. Kļūda rodas tikai gadījumos, kad ir ārkārtīgi liels lietotņu skaits, tāpēc šim nevajadzētu ietekmēt parastu lietotāju.</string>
+    <string name="settings_troubleshoot_diagnostic_running_status">Izpilda… (%1$d of %2$d)</string>
+    <string name="settings_notification_keyword_contains_invalid_character">Atslēgvārds nevar saturēt \'%s\'</string>
+    <string name="settings_notification_keyword_contains_dot">Atslēgvārds nevar sākties ar \'.\'</string>
+    <string name="settings_notification_new_keyword">Pievienot jaunu atslēgvārdu</string>
+    <string name="settings_notification_your_keywords">Jūsu atslēgvārdiem</string>
+    <string name="settings_notification_notify_me_for">Paziņot mani par</string>
+    <string name="settings_notification_other">Cits</string>
+    <string name="settings_notification_mentions_and_keywords">Atsauces un Atslēgvārdi</string>
+    <string name="settings_notification_default">Noklusējuma Paziņojumi</string>
+    <string name="settings_notification_emails_enable_for_email">Ieslēgt e-pasta paziņojumus priekš %s</string>
+    <string name="settings_notification_emails_no_emails">Lai saņemtu e-pastu ar paziņojumu, lūdzu, piesaistiet e-pastu savam Matrix kontam</string>
+    <string name="settings_notification_emails_category">E-pasta paziņojumi</string>
+    <string name="room_settings_none">Nekas</string>
+    <string name="room_settings_mention_and_keyword_only">Tikai Atsauces un Atslēgvārdi</string>
+    <string name="room_permissions_upgrade_the_space">Atjaunināt Telpu</string>
+    <string name="room_permissions_change_space_name">Nomainīt Telpas nosaukumu</string>
+    <string name="room_permissions_enable_space_encryption">Ieslēgt Telpas šifrēšanu</string>
+    <string name="room_permissions_change_main_address_for_the_space">Mainīt galveno Telpas adresi</string>
+    <string name="room_permissions_change_space_avatar">Mainīt Telpas avatāru</string>
+    <string name="space_permissions_notice_read_only">Jums nav atļaujas atjaunināt lomas, kas nepieciešamas, lai mainītu dažādas šīs telpas daļas</string>
+    <string name="space_permissions_notice">Izvēlaties lomas, kas nepieciešamas, lai mainītu dažādas Telpas daļas</string>
+    <string name="space_settings_permissions_subtitle">Skatiet un atjauniniet lomas, kas nepieciešamas, lai mainītu dažādas Telpas daļas.</string>
+    <string name="space_settings_permissions_title">Telpas atļaujas</string>
+    <string name="space_participants_unban_prompt_msg">Atceļot pievienošanās aizliegumu lietotājam, ļaus viņam atkal pievienoties Telpai.</string>
+    <string name="space_participants_ban_prompt_msg">Aizliedzot lietotājam pievienoties, viņš tiks izmests no šīs Telpas un vairs nevarēs tai pievienoties.</string>
+    <string name="space_participants_kick_prompt_msg">izmetot lietotāju, noņems viņu no šīs Telpas.
+\n
+\nLai novērstu viņu atkārtotu pievienošanos, jums tā vietā vajadzētu viņiem aizliegt pievienoties.</string>
+    <plurals name="format_time_d">
+        <item quantity="zero">%dd</item>
+        <item quantity="one">%dd</item>
+        <item quantity="other">%dd</item>
+    </plurals>
+    <plurals name="format_time_h">
+        <item quantity="zero">%dh</item>
+        <item quantity="one">%dh</item>
+        <item quantity="other">%dh</item>
+    </plurals>
+    <plurals name="format_time_m">
+        <item quantity="zero">%dm</item>
+        <item quantity="one">%dm</item>
+        <item quantity="other">%dm</item>
+    </plurals>
+    <string name="continue_anyway">Turpināt tāpat</string>
+    <string name="call_remove_jitsi_widget_progress">Beidz zvanu…</string>
+    <string name="call_ended_invite_timeout_title">Nav atbildes</string>
+    <string name="call_ended_user_busy_description">Lietotājs, kuram zvanījāt, ir aizņemts.</string>
+    <string name="call_ended_user_busy_title">Lietotājs aizņemts</string>
+    <string name="audio_call_with_participant">Zvans ar %s</string>
+    <string name="video_call_with_participant">Video zvans ar %s</string>
+    <plurals name="missed_video_call">
+        <item quantity="zero">Neatbildētu video zvanu</item>
+        <item quantity="one">Neatbildēts video zvans</item>
+        <item quantity="other">%d neatbildēti zvans</item>
+    </plurals>
+    <plurals name="missed_audio_call">
+        <item quantity="zero">Neatbildētu zvanu</item>
+        <item quantity="one">Neatbildēts zvans</item>
+        <item quantity="other">%d neatbildēti zvans</item>
+    </plurals>
+    <string name="call_ringing">Zvana…</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Izvēlaties Mājasserveri</string>
+    <string name="hs_client_url">Mājasservera API URL adrese</string>
+    <string name="login_error_homeserver_from_url_not_found">Nevar sasniegt mājasserveri URL adresē %s. Lūdzu, pārbaudiet saiti vai izvēlieties mājasserveri manuāli.</string>
+    <string name="use_as_default_and_do_not_ask_again">Izmantot pēc noklusējuma un neprasīt atkal</string>
+    <string name="option_always_ask">Vienmēr prasīt</string>
+    <string name="denied_permission_voice_message">Lai sūtītu balss ziņojumus, piešķiriet Mikrofona atļauju.</string>
+    <string name="spaces">Telpas</string>
+    <string name="learn_more">Uzziniet Vairāk</string>
+    <string name="notification_listening_for_notifications">Uztver paziņojumus</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-mk/strings.xml b/vector/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000000..a6b3daec93
--- /dev/null
+++ b/vector/src/main/res/values-mk/strings.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources></resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-pl/strings.xml b/vector/src/main/res/values-pl/strings.xml
index ebf188d1c3..49f71e478a 100644
--- a/vector/src/main/res/values-pl/strings.xml
+++ b/vector/src/main/res/values-pl/strings.xml
@@ -64,21 +64,22 @@
     <string name="notice_event_redacted_with_reason">Wiadomość usunięta [powód: %1$s]</string>
     <string name="notice_event_redacted_by_with_reason">Wiadomość usunięta przez %1$s [powód: %2$s]</string>
     <string name="notice_room_update">%s zakutalizował(a) ten pokój.</string>
-    <string name="initial_sync_start_importing_account">Synchronizacja początkowa:
+    <string name="initial_sync_start_importing_account">Wstępna synchronizacja:
 \nImportowanie konta…</string>
-    <string name="initial_sync_start_importing_account_crypto">Synchronizacja początkowa:
+    <string name="initial_sync_start_importing_account_crypto">Wstępna synchronizacja:
 \nImportowanie kryptografii</string>
-    <string name="initial_sync_start_importing_account_rooms">Synchronizacja początkowa:
-\nImportowanie Pokoi</string>
-    <string name="initial_sync_start_importing_account_joined_rooms">Synchronizacja początkowa:
-\nImportowanie dołączonych Pokoi</string>
-    <string name="initial_sync_start_importing_account_invited_rooms">Synchronizacja początkowa:
-\nImportowanie zaproszonych Pokoi</string>
-    <string name="initial_sync_start_importing_account_left_rooms">Synchronizacja początkowa:
-\nImportowanie opuszczonych Pokoi</string>
-    <string name="initial_sync_start_importing_account_groups">Synchronizacja początkowa:
-\nImportowanie Społeczności</string>
-    <string name="initial_sync_start_importing_account_data">Synchronizacja początkowa:
+    <string name="initial_sync_start_importing_account_rooms">Wstępna synchronizacja:
+\nImportowanie pokoi</string>
+    <string name="initial_sync_start_importing_account_joined_rooms">Wstępna synchronizacja:
+\nImportowanie Twoich konwersacji
+\nJeśli dołączyłeś(aś) do wielu pokoi, może to zająć dłuższą chwilę</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Wstępna synchronizacja:
+\nImportowanie zaproszonych pokoi</string>
+    <string name="initial_sync_start_importing_account_left_rooms">Wstępna synchronizacja:
+\nImportowanie opuszczonych pokoi</string>
+    <string name="initial_sync_start_importing_account_groups">Wstępna synchronizacja:
+\nImportowanie grup</string>
+    <string name="initial_sync_start_importing_account_data">Wstępna synchronizacja:
 \nImportowanie danych Konta</string>
     <string name="event_status_sending_message">Wysyłanie wiadomości…</string>
     <string name="clear_timeline_send_queue">Wyczyść kolejkę wysyłania</string>
@@ -103,7 +104,7 @@
     <string name="view_decrypted_source">Wyświetl odszyfrowane źródło</string>
     <string name="delete">Usuń</string>
     <string name="rename">Zmień nazwę</string>
-    <string name="report_content">Zgłoś zawartość</string>
+    <string name="report_content">Zgłoś treść</string>
     <string name="active_call">Aktywne połączenie</string>
     <string name="ongoing_conference_call">Przychodzące połączenie grupowe.
 \nDołącz z %1$s lub %2$s</string>
@@ -178,7 +179,7 @@
     <string name="create_account">Stwórz konto</string>
     <string name="login">Zaloguj się</string>
     <string name="logout">Wyloguj</string>
-    <string name="hs_url">Adres serwera</string>
+    <string name="hs_url">Adres serwera domowego</string>
     <string name="search">Szukaj</string>
     <string name="start_new_chat">Rozpocznij nową rozmowę</string>
     <string name="start_voice_call">Rozpocznij połączenie telefoniczne</string>
@@ -217,7 +218,7 @@
     <string name="auth_forgot_password">Zapomniałeś(-aś) hasła?</string>
     <string name="auth_use_server_options">Użyj niestandardowych ustawień serwera (zaawansowane)</string>
     <string name="auth_email_validation_message">Sprawdź swój adres e-mail, aby kontynuować rejestrację</string>
-    <string name="auth_recaptcha_message">Serwer chciałby upewnić się, czy nie jesteś robotem</string>
+    <string name="auth_recaptcha_message">Serwer domowy prosi o potwierdzenie, że nie jesteś robotem</string>
     <string name="auth_username_in_use">Nazwa użytkownika jest już używana</string>
     <string name="auth_reset_password_next_step_button">Zweryfikowałem adres e-mail</string>
     <string name="auth_reset_password_message">Aby przywrócić hasło, wprowadź adres e-mail powiązany z kontem:</string>
@@ -278,7 +279,7 @@ Przyznaj dostęp w następnym oknie.</string>
     <string name="join">Dołącz</string>
     <string name="preview">Podgląd</string>
     <string name="reject">Odrzuć</string>
-    <string name="room_jump_to_first_unread">Przejdź do pierwszej nieprzeczytanej wiadomości.</string>
+    <string name="room_jump_to_first_unread">Przejdź do pierwszej nieprzeczytanej wiadomości</string>
     <string name="room_preview_invitation_format">Zostałeś(-aś) zaproszony(-a) do tego pokoju przez %s</string>
     <string name="room_preview_try_join_an_unknown_room">Próbujesz uzyskać dostęp do %s. Czy chcesz dołączyć do pokoju, aby wziąć udział w dyskusji?</string>
     <string name="room_preview_try_join_an_unknown_room_default">pokój</string>
@@ -330,7 +331,7 @@ Przyznaj dostęp w następnym oknie.</string>
     <string name="room_resend_unsent_messages">Wyślij niewysłane wiadomości ponownie</string>
     <string name="room_delete_unsent_messages">Usuń niewysłane wiadomości</string>
     <string name="room_message_file_not_found">Nie znaleziono pliku</string>
-    <string name="room_do_not_have_permission_to_post">Nie masz uprawnień, aby pisać w tym pokoju</string>
+    <string name="room_do_not_have_permission_to_post">Nie masz uprawnień, aby pisać w tym pokoju.</string>
     <string name="ssl_trust">Ufaj</string>
     <string name="ssl_do_not_trust">Nie ufaj</string>
     <string name="ssl_logout_account">Wyloguj</string>
@@ -513,7 +514,7 @@ Zauważ, że ta czynność spowoduje ponowne uruchomienie aplikacji i może to t
     <string name="unknown_devices_alert_title">Pokój zawiera nieznane sesje</string>
     <string name="select_room_directory">Wybierz katalog pokojów</string>
     <string name="directory_server_fail_to_retrieve_server">Serwer może być wyłączony lub przeciążony</string>
-    <string name="directory_server_placeholder">Adres serwera domowego</string>
+    <string name="directory_server_placeholder">Nazwa serwera</string>
     <string name="directory_server_all_rooms_on_server">Wszystkie pokoje na serwerze %s</string>
     <string name="historical_placeholder">Szukaj w archiwum</string>
     <string name="font_size">Rozmiar czcionki</string>
@@ -566,8 +567,8 @@ Zauważ, że ta czynność spowoduje ponowne uruchomienie aplikacji i może to t
     <string name="auth_threepid_warning_message">Rejestracja jednocześnie za pomocą numeru telefonu i adresu e-mail nie jest obsługiwana dopóki nie pojawi się odpowiednie API. Tylko numer telefonu będzie brany pod uwagę.
 
 Możesz dodać adres e-mail do swojego profilu w ustawieniach.</string>
-    <string name="auth_home_server">Serwer Domowy:</string>
-    <string name="auth_identity_server">Serwer Tożsamości:</string>
+    <string name="auth_home_server">Serwer domowy:</string>
+    <string name="auth_identity_server">Serwer tożsamości:</string>
     <string name="auth_reset_password_success_message">Twoje hasło zostało zresetowane. Zostałeś wylogowany ze wszystkich sesji i nie będziesz więcej otrzymywać powiadomień push. Aby ponownie włączyć powiadomienia, zaloguj się ponownie na każdym urządzeniu.</string>
     <string name="login_error_unknown_token">Wprowadzony token dostępu nie został rozpoznany</string>
     <string name="login_error_bad_json">Uszkodzony JSON</string>
@@ -796,7 +797,7 @@ Czy chcesz dodać teraz kilka?</string>
     <string name="widget_integration_missing_user_id">Brakujące user_id w żądaniu.</string>
     <string name="widget_integration_missing_parameter">Brakuje wymaganego parametru.</string>
     <string name="widget_integration_invalid_parameter">Parametr jest niepoprawny.</string>
-    <string name="room_add_matrix_apps">Dodaj aplikacje Matrix</string>
+    <string name="room_add_matrix_apps">Zarządzaj integracjami</string>
     <string name="settings_labs_enable_send_voice">Wyślij wiadomości głosowe</string>
     <string name="you_added_a_new_device">Dodałeś(-aś) nową sesję \'%s\', która żąda kluczy szyfrujących.</string>
     <string name="your_unverified_device_requesting">Twoje niezweryfikowana sesja \'%s\' żąda kluczy szyfrujących.</string>
@@ -901,12 +902,12 @@ Widoczność wiadomości w Matrix jest podobna do wiadomości e-mail. Nasze zapo
     <string name="command_description_op_user">Określ poziom mocy użytkownika</string>
     <string name="command_description_deop_user">Usuwa opa użytkownikowi z podanym ID</string>
     <string name="command_description_invite_user">Zaprasza użytkownika z podanym ID do aktualnego pokoju</string>
-    <string name="command_description_join_room">Dołącza do pokoju z podanym aliasem</string>
+    <string name="command_description_join_room">Dołącza do pokoju o podanym adresie</string>
     <string name="command_description_topic">Ustawia temat pokoju</string>
     <string name="command_description_kick_user">Wyrzuca użytkownika z podanym ID</string>
     <string name="command_description_nick">Zmienia twój wyświetlany nick</string>
     <string name="command_description_clear_scalar_token">Do naprawiania zarządzania aplikacjami Matrix</string>
-    <string name="room_tombstone_versioned_description">Ten pokój został zamieniony i nie jest już aktywny</string>
+    <string name="room_tombstone_versioned_description">Ten pokój został zamieniony i nie jest już aktywny.</string>
     <string name="room_tombstone_continuation_link">Konwersacja jest kontynuowana tutaj</string>
     <string name="room_tombstone_continuation_description">Ten pokój jest kontynuacją innej rozmowy</string>
     <string name="resource_limit_exceeded_title">Limit pakietów został przekroczony</string>
@@ -1076,7 +1077,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="settings_notification_troubleshoot">Diagnostyka powiadomień</string>
     <string name="settings_troubleshoot_diagnostic">Rozwiązywanie problemów</string>
     <string name="settings_troubleshoot_diagnostic_success_status">Diagnostyka podstawowa nie wykazała problemów. Jeżeli wciąż nie otrzymujesz powiadomień, prosimy o przesłanie raportu o błędach, w celu ich rozwiązania.</string>
-    <string name="settings_notification_privacy_no_background_sync">Aplikacja <b>nie</b> potrzebuje łączyć się z serwerem domowym w tle, powinno to zredukować użycie baterii</string>
+    <string name="settings_notification_privacy_no_background_sync">Aplikacja <b>nie</b> potrzebuje łączyć się z serwerem domowym w tle, powinno to zmniejszyć użycie baterii</string>
     <string name="keys_backup_restore_with_passphrase_helper_with_link">Jeżeli nie pamiętasz swoich danych odzystkiwania, możesz %s.</string>
     <string name="keys_backup_restore_with_key_helper">Zgubiłeś (-łaś) swój klucz odzyskiwania\? Możesz ustawić nowy w ustawieniach.</string>
     <string name="keys_backup_settings_valid_signature_from_unverified_device">Kopia zapasowa posiada poprawną sygnaturę z niezweryfikowanej sesji %s</string>
@@ -1094,7 +1095,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">Dodaj Konto</string>
     <string name="settings_cryptography_manage_keys">Zarządzanie Kluczami Kryptograficznymi</string>
     <string name="settings_integration_allow">Zezwól na integracje</string>
-    <string name="settings_integration_manager">Menadżer Integracji</string>
+    <string name="settings_integration_manager">Menedżer Integracji</string>
     <string name="settings_fail_to_update_password_invalid_current_password">Hasło jest nieprawidłowe</string>
     <string name="passwords_do_not_match">Hasła nie pasują do siebie</string>
     <string name="compression_opt_list_choose">Wybierz</string>
@@ -1232,8 +1233,8 @@ Spróbuj uruchomić ponownie aplikację.</string>
 \n%1$s</string>
     <string name="template_settings_troubleshoot_test_fcm_failed_account_missing">[%1$s]
 \n${app_name} nie ma wpływu na wystąpienie tego problemu. Na tym urządzeniu nie ma konta Google. Otwórz menadżer kont i dodaj konto Google.</string>
-    <string name="settings_troubleshoot_test_token_registration_success">Token FCM z powodzeniem zarejestrowany na serwerze domowym.</string>
-    <string name="settings_troubleshoot_test_token_registration_failed">Niepowodzenie przy rejestracji tokena FCM na serwerze domowym:
+    <string name="settings_troubleshoot_test_token_registration_success">Token FCM pomyślnie zarejestrowany na serwerze domowym.</string>
+    <string name="settings_troubleshoot_test_token_registration_failed">Nieudana rejestracja tokena FCM na serwerze domowym:
 \n%1$s</string>
     <string name="settings_troubleshoot_test_service_restart_success">Usługa została zatrzymana i automatycznie uruchomiona ponownie.</string>
     <string name="settings_troubleshoot_test_service_restart_failed">Usługa nie uruchomiła się ponownie</string>
@@ -1254,7 +1255,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="auth_add_email_phone_message_2">Wprowadź adres e-mail, aby możliwe było odzyskiwanie konta. Opcjonalnie użyj adresu e-mail lub numeru telefonu aby móc zostać odkrytym przez znajomych.</string>
     <string name="auth_add_email_and_phone_message_2">Wprowadź adres e-mail, aby możliwe było odzyskiwanie konta. Opcjonalnie użyj adresu e-mail lub numeru telefonu aby móc zostać odkrytym przez znajomych.</string>
     <string name="settings_call_ringtone_use_default_stun">Pozwól na awaryjny serwer wspomagania połączeń</string>
-    <string name="settings_call_ringtone_use_default_stun_sum">Użyje %s aby wspomagać gdy Twój serwer domowy takiego nie ofertuje (Twój adres IP będzie udostępniony podczas połączenia)</string>
+    <string name="settings_call_ringtone_use_default_stun_sum">Użyj %s, gdy Twój serwer domowy takiego nie ofertuje (Twój adres IP będzie udostępniony podczas połączenia)</string>
     <string name="template_settings_troubleshoot_test_fcm_failed_too_many_registration">[%1$s]
 \nBłąd jest poza kontrolą ${app_name} i nawiązując do Google sygnalizuje on, iż urządzenie posiada zbyt wiele aplikacji zarejestrowanych z FCM. Błąd występuje jedynie w przypadku posiadania skrajnie wielu aplikacji, w związku z czym nie powinno dotknąć to normalnego użytkownika.</string>
     <string name="template_settings_troubleshoot_test_fcm_failed_service_not_available">[%1$s]
@@ -1280,8 +1281,8 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="settings_set_workmanager_delay">Preferowany interwał synchronizacji</string>
     <string name="settings_set_workmanager_delay_summary">%s
 \nSynchronizacja może zostać opóźniona w zależności od zasobów (bateria) lub stanu urządzenia (hibernacja).</string>
-    <string name="settings_integrations_summary">Użyj Menedżera Integracji aby zarządzać botami, mostami, widżetami oraz pakietami naklejek.
-\nMenadżerowie Integracji odbierają dane konfiguracji, mogą zmieniać widżety, wysyłać zaproszenia do pokoi oraz ustawiać poziomy uprawnień na Twoje żądanie.</string>
+    <string name="settings_integrations_summary">Użyj menedżera integracji aby zarządzać botami, mostami, widżetami i pakietami naklejek.
+\nMenedżerzy integracji odbierają dane konfiguracji, modyfikują widżety, wysyłają zaproszenia do pokoi i ustawiają poziomy uprawnień na Twe żądanie.</string>
     <string name="settings_inline_url_preview_summary">Pokaż podgląd linków wewnątrz czatu jeśli twój serwer wspiera tę funkcję.</string>
     <string name="settings_send_markdown_summary">Formatuj wiadomości używając składni Markdown zanim zostaną wysłane. Pozwala to na zaawansowane formatowanie takie jak używanie asterysków do wyświetlania tekstu w kursywie.</string>
     <string name="settings_show_join_leave_messages_summary">Nie wpływa to na zaproszenia, wyrzucenia oraz bany.</string>
@@ -1357,7 +1358,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="recovery_key_export_saved_as_warning">Klucz odzyskiwania został zapisany do \'%s\'.
 \n
 \nUwaga: plik może zostać usunięty, jeżeli aplikacja jest odinstalowana.</string>
-    <string name="keys_backup_setup_override_backup_prompt_tile">Kopia zapasowa już istnieje na Twoim serwerze domowym</string>
+    <string name="keys_backup_setup_override_backup_prompt_tile">Kopia zapasowa istnieje już na Twoim serwerze domowym</string>
     <string name="keys_backup_setup_override_backup_prompt_description">Wygląda na to, iż kopia zapasowa kluczy została skonfigurowana za pomocą innej sesji. Czy chcesz zastąpić ją tą, którą tworzysz\?</string>
     <string name="keys_backup_setup_step3_generating_key_status">Generowanie Klucza Odzyskiwania używając hasła, proces może zająć kilka sekund.</string>
     <string name="keys_backup_setup_backup_started_title">Kopia zapasowa uruchomiona</string>
@@ -1871,9 +1872,9 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="audio_meeting">Rozpocznij połączenie głosowe</string>
     <string name="video_meeting">Rozpocznij połączenie wideo</string>
     <string name="conference_call_in_progress">Połączenie grupowe już trwa!</string>
-    <string name="no_permissions_to_start_conf_call">Nie posiadasz wymaganych uprawnień aby rozpocząć połączenie grupowe w tym pokoju</string>
+    <string name="no_permissions_to_start_conf_call">Nie posiadasz uprawnień, aby rozpocząć połączenie grupowe w tym pokoju</string>
     <string name="no_permissions_to_start_webrtc_call_in_direct_room">Nie posiadasz wymaganych uprawnień do rozpoczęcia połączenia</string>
-    <string name="no_permissions_to_start_conf_call_in_direct_room">Nie posiadasz wymaganych uprawnień aby rozpocząć połączenie grupowe</string>
+    <string name="no_permissions_to_start_conf_call_in_direct_room">Nie posiadasz uprawnień, aby rozpocząć połączenie grupowe</string>
     <string name="alert_push_are_disabled_description">Przejrzyj swoje ustawienia aby włączyć powiadomienia PUSH</string>
     <string name="alert_push_are_disabled_title">Powiadomienia PUSH są wyłączone</string>
     <string name="failed_to_unban">Nie udało się odblokować użytkownika</string>
@@ -2040,7 +2041,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
         <item quantity="other">%d sek.</item>
     </plurals>
     <string name="settings_troubleshoot_test_push_loop_success">Aplikacja odebrała PUSH</string>
-    <string name="settings_troubleshoot_test_push_loop_title">Przetestuj wiadomość Push</string>
+    <string name="settings_troubleshoot_test_push_loop_title">Przetestuj powiadomienia push</string>
     <string name="room_participants_unban_title">Odbanuj użytkownika</string>
     <string name="room_participants_ban_reason">Powód zbanowania</string>
     <string name="room_participants_kick_prompt_msg">Wykopanie użytkownika spowoduje usunięcie go z tego pokoju.
@@ -2050,7 +2051,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="settings_call_show_confirmation_dialog_title">Zapobiegaj przypadkowym połączeniom</string>
     <string name="action_unpublish">Wycofaj publikację</string>
     <string name="action_add">Dodaj</string>
-    <string name="action_copy">Skopiuj</string>
+    <string name="action_copy">Kopiuj</string>
     <string name="call_notification_hangup">Zakończ rozmowę</string>
     <string name="reset">Zresetuj</string>
     <string name="no_connectivity_to_the_server_indicator_airplane">Tryb samolotowy jest włączony</string>
@@ -2089,7 +2090,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="login_error_outdated_homeserver_warning_content">Ten serwer domowy pracuje na starej wersji. Poproś jego administratora o zaktualizowanie go. Możesz kontynuować, ale niektóre funkcjonalności mogą nie działać poprawnie.</string>
     <string name="login_msisdn_notice">Użyj proszę formatu międzynarodowego (numer telefonu musi zaczynać się od \"+\")</string>
     <string name="login_server_url_form_common_notice">Wpisz adres serwera, którego chcesz używać</string>
-    <string name="direct_room_join_rules_invite_by_you">Zrobiłeś(-łaś) to dostępne tylko przez zaproszenie</string>
+    <string name="direct_room_join_rules_invite_by_you">Zrobiłeś(-łaś) to dostępne tylko przez zaproszenie.</string>
     <string name="room_join_rules_invite_by_you">Uczyniłeś(-łaś) ten pokój dostępnym tylko poprzez zaproszenie.</string>
     <string name="room_join_rules_public_by_you">Uczyniłeś(-łaś) ten pokój publicznym dla każdego kto zna link.</string>
     <string name="notice_member_no_changes_by_you">Nie dokonano żadnych zmian</string>
@@ -2193,7 +2194,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="settings_emails_and_phone_numbers_summary">Zarządzaj adresami e-mail oraz numerami telefonów powiązanymi z Twoim kontem Matrix</string>
     <string name="settings_emails_and_phone_numbers_title">Adresy e-mail i numery telefonów</string>
     <string name="disabled_integration_dialog_content">Włącz \"Zezwalaj na integracje\" w Ustawieniach żeby to zrobić.</string>
-    <string name="disabled_integration_dialog_title">Integracje są wyłączone</string>
+    <string name="disabled_integration_dialog_title">Integracje są zablokowane</string>
     <string name="reset_secure_backup_warning">To zastąpi obecny Klucz bądź Hasło.</string>
     <string name="reset_secure_backup_title">Wygeneruj nowy Klucz Bezpieczeństwa albo Hasło dla istniejącej kopii zapasowej.</string>
     <string name="settings_secure_backup_section_info">Zabezpiecza przeciwko utracie dostępu do zaszyfrowanych wiadomości oraz danych poprzez zapisanie zaszyfrowanych kluczy na Twoim serwerze.</string>
@@ -2284,7 +2285,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="settings_when_rooms_are_upgraded">Kiedy pokoje są aktualizowane</string>
     <string name="bootstrap_info_text">Zabezpiecz i odblokuj zaszyfrowane wiadomości oraz zaufane poprzez %s.</string>
     <string name="send_a_sticker">Naklejka</string>
-    <string name="direct_room_join_rules_invite">%1$s zrobił(a) to dostępne tylko z zaproszeniem.</string>
+    <string name="direct_room_join_rules_invite">%1$s wymaga otrzymania zaproszenia do dołączenia.</string>
     <plurals name="two_and_some_others_read">
         <item quantity="one">%1$s, %2$s i %3$d czyta</item>
         <item quantity="few">%1$s, %2$s i %3$d czytają</item>
@@ -2297,7 +2298,7 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="permissions_denied_add_contact">Zezwól na dostęp do Twoich kontaktów.</string>
     <string name="call_select_sound_device">Wybierz urządzenie dźwiękowe</string>
     <string name="template_call_failed_no_connection">Połączenie ${app_name} nieudane</string>
-    <string name="call_notification_reject">Zrezygnuj</string>
+    <string name="call_notification_reject">Odrzuć</string>
     <string name="start_chatting">Rozpocznij konwersację</string>
     <string name="matrix_to_card_title">Łącze Matrix</string>
     <string name="warning_unsaved_change_discard">Odrzuć zmiany</string>
@@ -2430,4 +2431,437 @@ Spróbuj uruchomić ponownie aplikację.</string>
     <string name="notice_room_invite_no_invitee_by_you">Twoje zaproszenie</string>
     <string name="summary_you_sent_sticker">Wysłałeś naklejkę.</string>
     <string name="summary_you_sent_image">Wysłałeś zdjęcie.</string>
+    <string name="room_create_member_of_space_name_can_join">Członkowie przestrzeni %s mogą znaleźć, podejrzeć i dołączyć.</string>
+    <string name="room_settings_room_access_restricted_description">Każdy w Przestrzeni z tym pokojem może go znaleźć i dołączyć. Tylko administratorzy mogą dodać go do przestrzeni.</string>
+    <string name="room_settings_room_access_restricted_title">Tylko członkowie Przestrzeni</string>
+    <string name="room_settings_space_access_public_description">Każdy może znaleźć Przestrzeń i do niej dołączyć</string>
+    <string name="room_settings_room_access_public_description">Każdy może znaleźć pokój i dołączyć</string>
+    <string name="room_settings_room_access_public_title">Publiczny</string>
+    <string name="room_settings_room_access_private_description">Tyko zaproszeni ludzie mogą znaleźć i dołączyć</string>
+    <string name="room_settings_room_access_private_invite_only_title">Prywatny (Tylko z zaproszeniem)</string>
+    <string name="room_settings_room_access_private_title">Prywatny</string>
+    <string name="room_settings_room_access_entry_unknown">Nieznane ustawienie dostępu (%s)</string>
+    <string name="room_settings_room_access_entry_knock">Każdy może zapukać do pokoju, członkowie mogą akceptować lub odrzucić</string>
+    <string name="space_settings_alias_subtitle">Przeglądaj i zarządzaj adresami tej Przestrzeni.</string>
+    <string name="space_settings_alias_title">Adresy Przestrzeni</string>
+    <string name="room_settings_guest_access_title">Zezwalaj gościom na dołączanie</string>
+    <string name="room_settings_space_access_title">Dostęp do Przestrzeni</string>
+    <string name="room_settings_access_rules_pref_dialog_title">Kto powinien mieć dostęp \?</string>
+    <string name="room_settings_room_notifications_account_settings">Ustawienia konta</string>
+    <string name="room_settings_room_notifications_manage_notifications">Możesz zarządzać notyfikacjami w %1$s.</string>
+    <string name="room_settings_room_notifications_encryption_notice">Proszę zwrócić uwagę, że notyfikacje o wzmiankach i słowach kluczowych nie są dostępne w zaszyfrowanych pokojach na urządzeniach mobilnych.</string>
+    <string name="room_settings_room_notifications_notify_me">Powiadamiaj mnie o</string>
+    <string name="settings_secure_backup_reset">Zresetuj bezpieczną kopię zapasową</string>
+    <string name="settings_secure_backup_setup">Skonfiguruj bezpieczną kopię zapasową</string>
+    <string name="settings_secure_backup_section_title">Bezpieczna kopia zapasowa</string>
+    <string name="settings_show_emoji_keyboard_summary">Dodaj przycisk otwierania klawiatury emoji w edytorze wiadomości</string>
+    <string name="settings_show_emoji_keyboard">Pokaż klawiaturę emoji</string>
+    <string name="settings_chat_effects_description">Użyj komendy /confetti lub wyślij wiadomość zawierająca ❄️ lub 🎉</string>
+    <string name="settings_chat_effects_title">Pokaż efekty chatu</string>
+    <string name="settings_mentions_and_keywords_encryption_notice">Nie będziesz dostawać powiadomień od wzmianek i słów kluczowych, w zaszyfrowanym pokoju na urządzeniu mobilnym.</string>
+    <string name="settings_troubleshoot_test_notification_title">Wyświetlanie powiadomień</string>
+    <string name="settings_notification_emails_enable_for_email">Aktywuj powiadomienia email dla %s</string>
+    <string name="settings_notification_emails_category">Powiadomienie email</string>
+    <string name="room_settings_none">Żadne</string>
+    <string name="room_settings_mention_and_keyword_only">Tylko wzmianki i słowa kluczowe</string>
+    <string name="notification_listening_for_notifications">Oczekiwanie na notyfikacje</string>
+    <string name="notice_room_canonical_alias_no_change">%1$s zmienił(a) adresy tego pokoju.</string>
+    <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Zmieniłeś(aś) głowny i alternatywny adres tego pokoju.</string>
+    <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s zmienił(a) główny i alternatywny adres tego pokoju.</string>
+    <string name="notice_room_canonical_alias_alternative_changed_by_you">Zmieniłeś alternatywny adres tego pokoju.</string>
+    <plurals name="notice_room_canonical_alias_alternative_removed_by_you">
+        <item quantity="one">Usunąłeś(aś) alternatywny adres %1$s dla tego pokoju.</item>
+        <item quantity="few">Usunąłeś(aś) alternatywne adresy %1$s dla tego pokoju.</item>
+        <item quantity="many"/>
+        <item quantity="other"/>
+    </plurals>
+    <string name="notice_room_canonical_alias_set">%1$s ustawił(a) główny adres tego pokoju na %2$s.</string>
+    <plurals name="notice_room_aliases_added">
+        <item quantity="one">%1$s dodał(a) %2$s jako adres tego pokoju.</item>
+        <item quantity="few">%1$s dodał(a) %2$s jako adresów tego pokoju.</item>
+        <item quantity="many">%1$s dodał(a) %2$s adresów tego pokoju.</item>
+        <item quantity="other">%1$s dodał(a) %2$s adresów tego pokoju.</item>
+    </plurals>
+    <string name="notice_room_third_party_registered_invite_with_reason_by_you">Zaakceptowałeś zaproszenie dla %1$s. Powód: %2$s</string>
+    <string name="notice_direct_room_join_with_reason_by_you">Dołączyłeś. Powód: %1$s</string>
+    <string name="notice_direct_room_join_with_reason">%1$s dołączył(a). Powód: %2$s</string>
+    <string name="notice_room_join_with_reason_by_you">Dołączyłeś do pokoju. Powód: %1$s</string>
+    <string name="notice_room_join_with_reason">%1$s dołączył do pokoju. Powód: %2$s</string>
+    <string name="notice_room_invite_you_with_reason">%1$s zaprosił Cię. Powód: %2$s</string>
+    <string name="notice_room_invite_with_reason_by_you">Zaprosiłeś %1$s. Powód: %2$s</string>
+    <string name="notice_room_invite_with_reason">%1$s zaprosił(a) %2$s. Powód: %3$s</string>
+    <string name="notice_room_invite_no_invitee_with_reason_by_you">Twoje zaproszenie. Powód: %1$s</string>
+    <string name="notice_room_invite_no_invitee_with_reason">Zaproszenie %1$s. Powód: %2$s</string>
+    <string name="notice_power_level_diff">%1$s z %2$s na %3$s</string>
+    <string name="notice_power_level_changed">%1$s zmienił(a) poziom mocy na %2$s.</string>
+    <string name="notice_power_level_changed_by_you">Zmieniłeś poziom mocy na %1$s.</string>
+    <string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Serwery z pasującymi literałami IP są teraz zablokowane.</string>
+    <string name="notice_room_server_acl_updated_ip_literals_allowed">• Serwery z pasującymi literałami IP są teraz dozwolone.</string>
+    <string name="notice_room_server_acl_updated_was_allowed">• Serwery pasujące do %s zostały usunięte z listy dozwolonych.</string>
+    <string name="notice_room_server_acl_updated_allowed">• Serwery pasujące do %s są teraz dozwolone.</string>
+    <string name="notice_room_server_acl_updated_was_banned">• Serwery pasujące do %s zostały usunięte z listy zablokowanych.</string>
+    <string name="notice_room_server_acl_updated_banned">• Serwery pasujące do %s są teraz zablokowane.</string>
+    <string name="room_displayname_3_members">%1$s, %2$s i %3$s</string>
+    <string name="link_this_email_with_your_account">%s w Ustawieniach, aby otrzymywać zaproszenia bezpośrednio w Elememencie.</string>
+    <string name="room_permissions_change_topic">Zmiana tematu</string>
+    <string name="room_permissions_upgrade_the_space">Aktualizacja Przestrzeni</string>
+    <string name="room_permissions_upgrade_the_room">Aktualizacja pokoju</string>
+    <string name="room_permissions_send_m_room_server_acl_events">Wysyłanie zdarzeń m.room.server_acl</string>
+    <string name="room_permissions_change_permissions">Zmiana uprawnień</string>
+    <string name="room_permissions_change_space_name">Zmiana nazwy Przestrzeni</string>
+    <string name="room_permissions_change_room_name">Zmiana nazwy pokoju</string>
+    <string name="room_permissions_change_history_visibility">Zmiana widoczności historii</string>
+    <string name="room_permissions_enable_space_encryption">Włączanie szyfrowania przestrzeni</string>
+    <string name="room_permissions_enable_room_encryption">Włączanie szyfrowania pokoju</string>
+    <string name="room_permissions_change_main_address_for_the_space">Zmiana głównego adresu Przestrzeni</string>
+    <string name="room_permissions_change_main_address_for_the_room">Zmiana głównego adresu pokoju</string>
+    <string name="room_permissions_change_space_avatar">Zmiana awatara Przestrzeni</string>
+    <string name="room_permissions_change_room_avatar">Zmiana awatara pokoju</string>
+    <string name="room_permissions_modify_widgets">Modyfikowanie widgetów</string>
+    <string name="room_permissions_notify_everyone">Powiadamianie wszystkich</string>
+    <string name="room_permissions_remove_messages_sent_by_others">Usuwanie wiadomości wysłanych przez inne osoby</string>
+    <string name="room_permissions_ban_users">Blokowanie użytkowników</string>
+    <string name="room_permissions_kick_users">Wyrzucanie użytkowników</string>
+    <string name="room_permissions_change_settings">Zmiana ustawień</string>
+    <string name="room_permissions_invite_users">Zapraszanie użytkowników</string>
+    <string name="room_permissions_send_messages">Wysyłanie wiadomości</string>
+    <string name="room_permissions_default_role">Rola domyślna</string>
+    <string name="space_permissions_notice_read_only">Nie masz uprawnień do modyfikowania roli wymaganych aby zmieniać poszczególne części tej przestrzeni</string>
+    <string name="room_permissions_notice_read_only">"Nie masz uprawnieni do modyfikowania roli wymaganych do zmiany  poszczególnych części pokoju"</string>
+    <string name="space_settings_permissions_subtitle">Przeglądaj i modyfikuj role wymagane do zmiany różnych części przestrzeni.</string>
+    <string name="room_permissions_notice">Wybierz role wymagane do zmieniania poszczególnych części pokoju</string>
+    <string name="space_permissions_notice">Wybierz role wymagane do zmiany poszczególnych części tej przestrzeni</string>
+    <string name="room_permissions_title">Uprawnienia</string>
+    <string name="room_settings_permissions_subtitle">Przeglądaj i modyfikuj role wymagane do zmiany różnych funkcji pokoju.</string>
+    <string name="space_settings_permissions_title">Uprawnienia Przestrzeni</string>
+    <string name="room_settings_permissions_title">Uprawnienia pokoju</string>
+    <string name="space_participants_unban_prompt_msg">Odblokowanie użytkownika pozwoli mu na ponowne dołączenie do tej przestrzeni.</string>
+    <string name="space_participants_ban_prompt_msg">Blokowanie użytkowników wyrzuci ich z tej przestrzeni i uniemożliwi im dołączenie ponownie.</string>
+    <string name="room_participants_leave_private_warning">Ten pokój jest prywatny. Nie będziesz w stanie dołączyć bez zaproszenia.</string>
+    <string name="continue_anyway">Kontynuuj mimo wszystko</string>
+    <string name="call_remove_jitsi_widget_progress">Zakańczanie połączenia…</string>
+    <string name="call_ended_invite_timeout_title">Brak odpowiedzi</string>
+    <string name="call_ended_user_busy_description">Użytkownik, do którego dzwoniłeś, jest teraz zajęty.</string>
+    <string name="call_ended_user_busy_title">Użytkownik zajęty</string>
+    <string name="call_held_by_you">Zawiesiłeś(aś) połączenie</string>
+    <string name="call_held_by_user">%s zawiesił(a) połączenie</string>
+    <string name="call_hold_action">Zawieś</string>
+    <string name="call_resume_action">Wznów</string>
+    <string name="return_to_call">Wróć do rozmowy</string>
+    <string name="audio_call_with_participant">Połączenie głosowe z %s</string>
+    <string name="video_call_with_participant">Połączenie wideo z %s</string>
+    <plurals name="missed_video_call">
+        <item quantity="one">Nieodebrane połączenie wideo</item>
+        <item quantity="few">%d nieodebrane połączenia wideo</item>
+        <item quantity="many">%d nieodebranych połączeń wideo</item>
+        <item quantity="other">%d nieodebranych połączeń wideo</item>
+    </plurals>
+    <plurals name="missed_audio_call">
+        <item quantity="one">Nie odebrane połączenie głosowe</item>
+        <item quantity="few">%d nie odebrane połączenia głosowe</item>
+        <item quantity="many">%d nie odebranych połączeń głosowych</item>
+        <item quantity="other">%d nie odebranych połączeń głosowych</item>
+    </plurals>
+    <string name="call_ringing">Połączenie przychodzące…</string>
+    <string name="error_unauthorized">Błąd autoryzacji, niepoprawne dane logowania</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Wybierz serwer domowy</string>
+    <string name="login_error_homeserver_from_url_not_found">Nie można było połączyć się z serwerem domowym %s. Proszę sprawdzić link lub wybrać serwer domowy manualnie.</string>
+    <string name="use_as_default_and_do_not_ask_again">Używaj jako domyślne i nie pytaj ponownie</string>
+    <string name="option_always_ask">Zawsze pytaj</string>
+    <string name="hs_client_url">Adres URL serwera domowego</string>
+    <string name="send_bug_report_include_key_share_history">Wyślij historię żądań udostępnienia klucza</string>
+    <string name="spaces_header">Przestrzenie</string>
+    <string name="spaces_invited_header">Zaproszenia</string>
+    <string name="settings_category_room_directory">Katalog pokoi</string>
+    <string name="suggested_header">Sugerowane pokoje</string>
+    <string name="dialog_edit_hint">Nowa wartość</string>
+    <string name="action_return">Wróć</string>
+    <string name="action_switch">Przełącz</string>
+    <string name="missing_permissions_title">Brak uprawnień</string>
+    <string name="denied_permission_voice_message">Proszę nadać uprawnienia do mikrofonu, aby nagrywać wiadomości głosowe.</string>
+    <string name="denied_permission_camera">Aby wykonać tą akcję, proszę nadać uprawnienia do aparatu z poziomu ustawień systemowych.</string>
+    <string name="denied_permission_generic">Brakuje uprawnień do wykonania tej akcji, proszę je przydzielić z poziomu ustawień systemowych.</string>
+    <string name="spaces">Przestrzenie</string>
+    <string name="learn_more">Dowiedz się więcej</string>
+    <string name="system_theme">Domyślny systemu</string>
+    <string name="notice_end_to_end_unknown_algorithm_by_you">Włączyłeś(aś) szyfrowanie end-to-end (nierozpoznany algorytm %1$s).</string>
+    <string name="notice_end_to_end_unknown_algorithm">%1$s włączył(a) szyfrowanie end-to-end (nierozpoznany algorytm: %2$s).</string>
+    <string name="notice_end_to_end_ok_by_you">Włączyłeś(aś) szyfrowanie end-to-end.</string>
+    <string name="notice_end_to_end_ok">%1$s włączył(a) szyfrowanie end-to-end.</string>
+    <string name="notice_direct_room_guest_access_forbidden_by_you">Zabroniłeś(aś) gościom dołączać do pokoju.</string>
+    <string name="notice_direct_room_guest_access_forbidden">%1$s zabronił(a) gościom dołączać do pokoju.</string>
+    <string name="notice_room_guest_access_forbidden_by_you">Zabroniłeś gościom dołączać do pokoju.</string>
+    <string name="notice_room_guest_access_forbidden">%1$s zabronił(a) gościom dołączać do pokoju.</string>
+    <string name="notice_direct_room_guest_access_can_join_by_you">Zezwoliłeś gościom na dołączanie tutaj.</string>
+    <plurals name="notice_room_canonical_alias_alternative_removed">
+        <item quantity="one">%1$s usunął(ęła) alternatywny adres %2$s dla tego pokoju.</item>
+        <item quantity="few">%1$s usunął(ęła) alternatywne adresy %2$s dla tego pokoju.</item>
+        <item quantity="many">%1$s usunął(ęła) alternatywne adresy %2$s dla tego pokoju.</item>
+        <item quantity="other">%1$s usunął(ęła) alternatywne adresy %2$s dla tego pokoju.</item>
+    </plurals>
+    <plurals name="notice_room_canonical_alias_alternative_added_by_you">
+        <item quantity="one">Dodałeś(aś) alternatywny adres %1$s dla tego pokoju.</item>
+        <item quantity="few">Dodałeś(aś) alternatywne adresy %1$s dla tego pokoju.</item>
+        <item quantity="many">Dodałeś(aś) alternatywne adresy %1$s dla tego pokoju.</item>
+        <item quantity="other">Dodałeś(aś) alternatywne adresy %1$s dla tego pokoju.</item>
+    </plurals>
+    <plurals name="notice_room_canonical_alias_alternative_added">
+        <item quantity="one">%1$s dodał(a) alternatywny adres %2$s dla tego pokoju.</item>
+        <item quantity="few">%1$s dodał(a) alternatywne adresy %2$s dla tego pokoju.</item>
+        <item quantity="many">%1$s dodał(a) alternatywne adresy %2$s dla tego pokoju.</item>
+        <item quantity="other">%1$s dodał(a) alternatywne adresy %2$s dla tego pokoju.</item>
+    </plurals>
+    <string name="notice_room_canonical_alias_unset_by_you">Usunąłeś(aś) główny adres tego pokoju.</string>
+    <string name="notice_room_canonical_alias_unset">%1$s usunął(a) główny adres tego pokoju.</string>
+    <string name="notice_room_canonical_alias_set_by_you">Ustawiłeś(aś) główny adres tego pokoju na %1$s.</string>
+    <string name="notice_widget_jitsi_modified_by_you">Zmodyfikowałeś(aś) wideokonferencję</string>
+    <string name="notice_widget_jitsi_modified">Wideokonferencja zmodyfikowana przez %1$s</string>
+    <string name="notice_widget_jitsi_removed_by_you">Zakończyłeś wideokonferencję</string>
+    <string name="notice_widget_modified_by_you">Zmodyfikowałeś(aś) widget %1$s</string>
+    <string name="notice_widget_modified">%1$s zmodyfikował(a) widget %2$s</string>
+    <string name="notice_widget_removed_by_you">Usunąłeś(aś) widget %1$s</string>
+    <string name="notice_widget_removed">%1$s usunął(ęła) widget %2$s</string>
+    <string name="notice_widget_added_by_you">Dodałeś widget %1$s</string>
+    <string name="notice_widget_added">%1$s dodał(a) widżet %2$s</string>
+    <string name="notice_room_third_party_registered_invite_by_you">Zaakceptowałeś zaproszenie dla %1$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite_by_you">Anulowałeś zaproszenie dla %1$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite">%1$s anulował zaproszenie dla %2$s</string>
+    <string name="notice_room_third_party_revoked_invite_by_you">Anulowałeś zaproszenie dla %1$s do dołączenia do pokoju</string>
+    <string name="notice_room_third_party_revoked_invite">%1$s odwołał zaproszenie dla %2$s do dołączenia do pokoju</string>
+    <string name="settings_developer_mode_show_info_on_screen_summary">Pokaż przydatne informacje aby pomóc w naprawianiu aplikacji</string>
+    <string name="settings_developer_mode_show_info_on_screen_title">Pokazuj informacje diagnostyczne na ekranie</string>
+    <string name="settings_messages_containing_display_name">Moja nazwa wyświetlana</string>
+    <string name="settings_messages_containing_username">Moja nazwa użytkownika</string>
+    <string name="settings_messages_direct_messages">Wiadomości bezpośrednie</string>
+    <string name="settings_messages_by_bot">Wiadomości od bota</string>
+    <string name="settings_room_invitations">Zaproszenia do pokoju</string>
+    <string name="settings_messages_containing_keywords">Słowa kluczowe</string>
+    <string name="settings_mentions_at_room">\@pokój</string>
+    <string name="settings_encrypted_group_messages">Zaszyfrowane wiadomości grupowe</string>
+    <string name="settings_group_messages">Wiadomości grupowe</string>
+    <string name="settings_encrypted_direct_messages">Zaszyfrowane wiadomości bezposrednie</string>
+    <string name="settings_notification_keyword_contains_invalid_character">Słowa kluczowe nie mogą zawierać \'%s\'</string>
+    <string name="settings_notification_keyword_contains_dot">Słowa kluczowe nie mogą zaczynać się od \'.\'</string>
+    <string name="settings_notification_new_keyword">Dodaj nowe słowo kluczowe</string>
+    <string name="settings_notification_your_keywords">Twoje słowa kluczowe</string>
+    <string name="settings_notification_notify_me_for">Powiadamiaj mnie o</string>
+    <string name="settings_notification_other">Inne</string>
+    <string name="settings_notification_mentions_and_keywords">Wzmianki i słowa kluczowe</string>
+    <string name="settings_notification_default">Domyślne powiadomienia</string>
+    <string name="settings_notification_emails_no_emails">Aby otrzymywać emaile z notyfikacjami, proszę przypisać email do swojego konta Matrix</string>
+    <string name="voice_message_reply_content">Wiadomość głosowa (%1$s)</string>
+    <string name="error_voice_message_cannot_reply_or_edit">Nie można odpowiadać lub edytować kiedy wiadomość głosowa jest aktywna</string>
+    <string name="error_voice_message_unable_to_record">Nie udało się nagrać wiadomości głosowej</string>
+    <string name="error_voice_message_unable_to_play">Nie można odtworzyć tej wiadomości głosowej</string>
+    <string name="labs_use_voice_message">Włącz wiadomość głosową</string>
+    <string name="voice_message_tap_to_stop_toast">Naciśnij na swoje nagranie aby zatrzymać lub przesłuchać</string>
+    <string name="voice_message_n_seconds_warning_toast">zostało %1$ds</string>
+    <string name="voice_message_release_to_send_toast">Przytrzymaj aby nagrać, puść by wysłać</string>
+    <string name="voice_message_slide_to_cancel">Przeciągnij aby anulować</string>
+    <string name="a11y_start_voice_message">Nagraj wiadomość głosową</string>
+    <string name="call_jitsi_started">Rozmowa grupowa rozpoczęta</string>
+    <string name="error_failed_to_join_room">Przepraszamy, wystąpił błąd podczas dołączania do: %s</string>
+    <string name="upgrade_required">Wymagana aktualizacja</string>
+    <string name="upgrade">Aktualizacja</string>
+    <string name="it_may_take_some_time">Prosimy o cierpliwość, to może zając chwilę.</string>
+    <string name="unnamed_room">Pokój bez nazwy</string>
+    <string name="this_space_has_no_rooms_admin">Niektóre pokoje mogą być ukryte, gdyż są prywatne i wymagają od Ciebie zaproszenia.</string>
+    <string name="this_space_has_no_rooms_not_admin">Niektóre pokoje mogą być ukryte, gdyż są prywatne i wymagają od Ciebie zaproszenia. 
+\nNie masz uprawnień aby dodawać pokoje.</string>
+    <string name="this_space_has_no_rooms">W tej Przestrzeni nie ma żadnych pokoi</string>
+    <string name="spaces_no_server_support_description">Proszę skontaktować się z administratorem Twojego serwera domowego aby uzyskać więcej informacji</string>
+    <string name="spaces_no_server_support_title">Wygląda na to, że Twój serwer domowy jeszcze nie obsługuje Przestrzeni</string>
+    <string name="spaces_feeling_experimental_subspace">Lubisz eksperymentować\?
+\nMożesz dodać istniejącą Przestrzeń do innej Przestrzeni.</string>
+    <string name="all_rooms_youre_in_will_be_shown_in_home">Wszystkie pokoje, w których jesteś będą pokazywane na ekranie domowym.</string>
+    <string name="preference_show_all_rooms_in_home">Pokaż wszystkie pokoje w ekranie domowym</string>
+    <string name="space_manage_rooms_and_spaces">Zarządzaj pokojami oraz przestrzeniami</string>
+    <string name="space_mark_as_not_suggested">Oznacz jako nie sugerowana</string>
+    <string name="space_mark_as_suggested">Oznacz jako sugerowana</string>
+    <string name="space_suggested">Sugerowane</string>
+    <string name="make_this_space_public">Ustaw tą Przestrzeń jako publiczną</string>
+    <string name="space_settings_manage_rooms">Zarządzaj pokojami</string>
+    <string name="looking_for_someone_not_in_space">Szukasz kogoś , kto nie jest w %s\?</string>
+    <string name="user_invites_you">%s Cię zaprasza</string>
+    <string name="labs_use_restricted_join_rule_desc">Ostrzeżenie! Wymaga wsparcia serwera oraz eksperymentalnej wersji pokoju</string>
+    <string name="labs_use_restricted_join_rule">Przestrzeń eksperymentalna - Pokój ograniczony.</string>
+    <string name="you_are_invited">Zostałeś zaproszony</string>
+    <string name="spaces_beta_welcome_to_spaces_desc">Przestrzenie są nową metodą na zarządzanie pokojami i osobami.</string>
+    <string name="spaces_beta_welcome_to_spaces">Witamy w Przestrzeniach!</string>
+    <string name="space_add_rooms">Dodaj pokoje</string>
+    <string name="space_add_space_to_any_space_you_manage">Dodaj przestrzeń do jakiejkolwiek przestrzeni którą zarządzasz.</string>
+    <string name="space_add_existing_spaces">Dodaj istniejące przestrzenie</string>
+    <string name="space_add_existing_rooms_only">Dodaj istniejące pokoje</string>
+    <string name="space_add_existing_rooms">Dodaj istniejące pokoje i przestrzenie</string>
+    <string name="pick_tings_to_leave">Wybierz aby opuścić</string>
+    <string name="leave_specific_ones">Opuść wybrane pokoje i przestrzenie…</string>
+    <string name="dont_leave_any">Nie opuszczaj żadnych pokoi i przestrzeni</string>
+    <string name="you_will_leave_all_in">Opuścisz wszystkie pokoje i przestrzenie w %s.</string>
+    <string name="leave_all_rooms_and_spaces">Opuść wszystkie pokoje i przestrzenie</string>
+    <string name="space_leave_prompt_msg_as_admin">Jesteś jedynym administratorem tej przestrzeni. Opuszczenie jej oznacza brak kontroli nad nią.</string>
+    <string name="space_leave_prompt_msg_private">Nie będziesz w stanie ponownie dołączyć, do momentu kiedy nie zostaniesz ponownie zaproszony.</string>
+    <string name="space_leave_prompt_msg_only_you">Jesteś jedyną osoba tutaj. Jeśli wyjdziesz, nikt nie będzie w stanie dołączyć w przyszłości, włączając Ciebie.</string>
+    <string name="space_leave_prompt_msg_with_name">Czy jesteś pewny, że chcesz opuścić %s\?</string>
+    <string name="leave_space">Opuść przestrzeń</string>
+    <string name="space_add_child_title">Dodawaj pokoje</string>
+    <string name="space_explore_activity_title">Przeglądaj pokoje</string>
+    <string name="suggested_rooms_pills_on_empty_header">Witaj w %1$s, %2$s.</string>
+    <string name="suggested_rooms_pills_on_empty_text">Jeszcze nie jesteś w żadnym pokoju. Poniżej znajdują się proponowane, możesz też zobaczyć więcej naciskając zielony przycisk na dole po prawej.</string>
+    <string name="finish_setup">Ukończ konfigurację</string>
+    <string name="discovery_invite">Zaproś przez email, znajdź kontakty i więcej…</string>
+    <string name="create_space_identity_server_info_none">Aktualnie nie używasz serwera tożsamości. Aby zapraszać znajomych i być dla nich widoczny, skonfiguruj go poniżej.</string>
+    <string name="room_alias_preview_not_found">Ten alias na razie nie jest dostępny.
+\nSpróbuj ponownie później lub zapytaj administratora tego pokoju czy masz dostęp.</string>
+    <string name="join_anyway">Dołącz pomimo to</string>
+    <string name="join_space">Dołącz do przestrzeni</string>
+    <string name="create_space">Stwórz przestrzeń</string>
+    <string name="skip_for_now">Na razie pomiń</string>
+    <string name="share_space_link_message">Dołącz do mojej przestrzeni %1$s %2$s</string>
+    <string name="invite_just_to_this_room_desc">Nie będą częścią %s</string>
+    <string name="invite_just_to_this_room">Tylko do tego pokoju</string>
+    <string name="invite_to_space_with_name_desc">Będą w stanie przeglądać %s</string>
+    <string name="invite_to_space_with_name">Zaproś do %s</string>
+    <string name="invite_by_link">Udostępnij link</string>
+    <string name="invite_by_mxid_or_mail">Zaproś przez nazwę użytkownika lub email</string>
+    <string name="invite_by_mxid">Zaproś przez nazwę użytkownika</string>
+    <string name="invite_by_email">Zaproś przez email</string>
+    <string name="invite_people_to_your_space_desc">Aktualnie jesteś tylko Ty. %s będzie jeszcze lepsza kiedy dołączą inni.</string>
+    <string name="invite_to_space">Zaproś do %s</string>
+    <string name="invite_people_menu">Zaproś osoby</string>
+    <string name="invite_people_to_your_space">Zaproś osoby do Twojej przestrzeni</string>
+    <string name="create_space_topic_hint">Opis</string>
+    <string name="create_spaces_loading_message">Tworzenie przestrzeni…</string>
+    <string name="create_spaces_default_public_random_room_name">Losowy</string>
+    <string name="create_spaces_default_public_room_name">Ogólny</string>
+    <string name="create_spaces_invite_public_header">Kim są Twoi znajomi \?</string>
+    <string name="create_spaces_room_public_header_desc">Stworzymy dla nich pokoje. Możesz też dodać następne w późniejszym etapie.</string>
+    <string name="create_spaces_room_public_header">Jaki rodzaj dyskusji chcesz mieć w %s\?</string>
+    <string name="create_space_error_empty_field_space_name">Nadaj nazwę aby kontynuować.</string>
+    <string name="activity_create_space_title">Stwórz przestrzeń</string>
+    <string name="space_type_private_desc">Tylko z zaproszeniem, najlepsza dla Ciebie lub zespołów</string>
+    <string name="space_type_private">Prywatna</string>
+    <string name="space_type_public_desc">Otwarta dla każdego, najlepsza dla społeczności</string>
+    <string name="space_type_public">Publiczna</string>
+    <string name="create_spaces_private_teammates">Prywatna przestrzeń dla Ciebie i Twoich znajomych</string>
+    <string name="create_spaces_me_and_teammates">Ja i moi znajomi</string>
+    <string name="create_spaces_organise_rooms">Prywatna przestrzeń do organizacji Twoich pokoi</string>
+    <string name="create_spaces_just_me">Tylko ja</string>
+    <string name="create_spaces_make_sure_access">Upewnij się, że odpowiednie osoby mają dostęp do %s. Możesz zmienić to później.</string>
+    <string name="create_spaces_who_are_you_working_with">Z kim pracujesz\?</string>
+    <string name="create_spaces_join_info_help">Aby dołączyć do istniejącej przestrzeni, potrzebujesz zaproszenia.</string>
+    <string name="create_spaces_you_can_change_later">Możesz zmienić to później</string>
+    <string name="create_spaces_choose_type_label">Jaki rodzaj przestrzeni chcesz stworzyć\?</string>
+    <string name="create_spaces_type_header">Przestrzenie są nowym sposobem na organizację pokojów i osób</string>
+    <string name="event_status_sent_message">Wiadomość wysłana</string>
+    <string name="initial_sync_start_downloading">Wstępna synchronizacja:
+\nPobieranie danych…</string>
+    <string name="initial_sync_start_server_computing">Wstępna synchronizacja: 
+\nCzekanie na odpowiedź serwera…</string>
+    <string name="room_displayname_empty_room_was">Pusty pokój (było %s)</string>
+    <plurals name="room_displayname_four_and_more_members">
+        <item quantity="one">%1$s, %2$s, %3$s i %4$d innych</item>
+        <item quantity="few">%1$s, %2$s, %3$s i %4$d innych</item>
+        <item quantity="many"/>
+        <item quantity="other"/>
+    </plurals>
+    <string name="room_displayname_4_members">%1$s, %2$s, %3$s i %4$s</string>
+    <string name="power_level_custom_no_value">Niestandardowe</string>
+    <string name="power_level_custom">Niestandardowe (%1$d)</string>
+    <string name="power_level_default">Domyślne</string>
+    <string name="power_level_moderator">Moderator</string>
+    <string name="power_level_admin">Administrator</string>
+    <string name="notice_widget_jitsi_removed">Wideokonferencja zakończona przez %1$s</string>
+    <string name="notice_widget_jitsi_added_by_you">Rozpocząłeś wideokonferencję</string>
+    <string name="notice_widget_jitsi_added">Wideokonferencja rozpoczęta przez %1$s</string>
+    <string name="notice_room_third_party_invite_by_you">Wysłałeś zaproszenie do %1$s aby dołączył do pokoju</string>
+    <string name="notice_profile_change_redacted_by_you">Zaktualizowałeś swój profil %1$s</string>
+    <string name="notice_room_avatar_removed_by_you">Usunąłeś(aś) awatar pokoju</string>
+    <string name="notice_room_name_removed_by_you">Usunąłeś(aś) nazwę pokoju</string>
+    <string name="notice_room_server_acl_updated_title_by_you">Zmieniłeś listę kontroli dostępu ACL dla tego pokoju.</string>
+    <string name="notice_room_server_acl_updated_title">%s zmienił listę kontroli dostępu (ACL) dla tego pokoju.</string>
+    <string name="notice_room_server_acl_set_ip_literals_not_allowed">• Dopasowywanie serwerów po ciągach IP jest zabronione.</string>
+    <string name="notice_room_server_acl_set_ip_literals_allowed">• Dozwolone jest dopasowywanie serwera po ciągach IP.</string>
+    <string name="notice_room_ban_with_reason">%1$s zbanował(a) %2$s. Powód: %3$s</string>
+    <string name="notice_room_unban_with_reason_by_you">Odbanowałeś(aś) %1$s. Powód: %2$s</string>
+    <string name="notice_room_unban_with_reason">%1$s zdjął(ęła) bana %2$s. Powód: %3$s</string>
+    <string name="notice_room_kick_with_reason_by_you">Wyrzuciłeś(aś) %1$s. Powód: %2$s</string>
+    <string name="notice_requested_voip_conference_by_you">Zażądałeś konferencji VoIP</string>
+    <string name="notice_room_server_acl_allow_is_empty">🎉 Wszystkie serwery zostały zbanowane od uczestnictwa. Ten pokój nie może być już używany.</string>
+    <string name="notice_room_server_acl_updated_no_change">Bez zmian.</string>
+    <string name="notice_direct_room_third_party_invite_by_you">Zaprosiłeś %1$s</string>
+    <string name="notice_direct_room_third_party_invite">%1$s zaprosił %2$s</string>
+    <string name="notice_direct_room_guest_access_can_join">%1$s zezwolił gościom dołączać do tego pokoju.</string>
+    <string name="notice_room_guest_access_can_join_by_you">Zezwoliłeś gościom na dołączanie do tego pokoju.</string>
+    <string name="notice_room_guest_access_can_join">%1$s zezwolił gościom dołączać do tego pokoju.</string>
+    <string name="notice_room_canonical_alias_no_change_by_you">Zmieniłeś adres tego pokoju.</string>
+    <string name="notice_room_avatar_removed">%1$s usunął avatar pokoju</string>
+    <string name="notice_room_topic_removed_by_you">Usunąłeś temat pokoju</string>
+    <string name="notice_room_third_party_registered_invite_with_reason">%1$s zaakceptował zaproszenie dla %2$s. Powód: %3$s</string>
+    <string name="notice_room_third_party_revoked_invite_with_reason_by_you">Wycofałeś zaproszenie do pokoju dla %1$s. Powód: %2$s</string>
+    <string name="notice_room_third_party_revoked_invite_with_reason">%1$s wycofał zaproszenie do pokoju dla %2$s. Powód: %3$s</string>
+    <string name="notice_room_third_party_invite_with_reason_by_you">Wysłałeś zaproszenie do pokoju do %1$s. Powód: %2$s</string>
+    <string name="notice_room_third_party_invite_with_reason">%1$s wysłał zaproszenie do pokoju do %2$s . Powód: %3$s</string>
+    <string name="notice_room_ban_with_reason_by_you">Zbanowałeś %1$s. Powód: %2$s</string>
+    <string name="notice_room_kick_with_reason">%1$s wyrzucił %2$s. Powód: %3$s</string>
+    <string name="notice_room_reject_with_reason_by_you">Odrzuciłeś/aś zaproszenie. Powód: %1$s</string>
+    <string name="notice_room_reject_with_reason">%1$s odrzucił/a zaproszenie. Powód: %2$s</string>
+    <string name="notice_direct_room_leave_with_reason_by_you">Wyszedłeś. Powód: %1$s</string>
+    <string name="notice_direct_room_leave_with_reason">%1$s wyszedł. Powód: %2$s</string>
+    <string name="notice_room_leave_with_reason_by_you">Opuściłeś/aś pokój. Powód: %1$s</string>
+    <string name="notice_room_leave_with_reason">%1$s opuścił/a pokój. Powód: %2$s</string>
+    <string name="audio_video_meeting_description">Spotkania wykorzystują polityki bezpieczeństwa i uprawnień Jitsi. Wszystkie osoby obecne w danej chwili w pokoju zobaczą zaproszenie do dołączenia w momencie rozpoczęcia spotkania.</string>
+    <string name="settings_discovery_no_policy_provided">Serwer tożsamości nie udostępnił swojej polityki</string>
+    <string name="settings_discovery_hide_identity_server_policy_title">Ukryj politykę serwera tożsamości</string>
+    <string name="settings_discovery_show_identity_server_policy_title">Wyświetl politykę serwera tożsamości</string>
+    <string name="open_discovery_settings">Otwórz ustawienia Poznawania</string>
+    <string name="search_hint_room_name">Wyszukaj nazwę</string>
+    <string name="user_directory_search_hint_2">Wyszukaj po nazwie, ID lub mailu</string>
+    <string name="send_file_step_compressing_video">Kompresowanie filmu %d%%</string>
+    <string name="send_file_step_compressing_image">Kompresowanie obrazu…</string>
+    <string name="give_feedback">Podziel się opinią</string>
+    <string name="feedback_failed">Nie udało się przesłać opinii (%s)</string>
+    <string name="feedback_sent">Dziękujemy, Twoja opinia została wysłana</string>
+    <string name="you_may_contact_me">Zachęcamy do kontaktu, jeśli masz dodatkowe pytania</string>
+    <string name="send_feedback_space_info">Używasz przestrzeni w wersji beta. Ta opinia pomoże nam w tworzeniu kolejnych wersji. Twoja platforma i nazwa użytkownika zostaną odnotowane, abyśmy mogli w pełni wykorzystać Twoje sugestie.</string>
+    <string name="send_feedback_space_title">Prześlij opinię o przestrzeniach</string>
+    <string name="create_new_space">Stwórz nową przestrzeń</string>
+    <string name="command_description_whois">Wyświetla informacje o użytkowniku</string>
+    <string name="command_description_avatar_for_room">Zmienia Twój awatar tylko w tym pokoju</string>
+    <string name="command_description_room_avatar">Zmienia awatar obecnego pokoju</string>
+    <string name="command_description_nick_for_room">Zmienia Twój wyświetlany pseudonim tylko w tym pokoju</string>
+    <string name="command_description_room_name">Ustawia nazwę pokoju</string>
+    <string name="command_description_unignore_user">Przestaje ignorować użytkownika, od teraz jego wiadomości będą dla Ciebie widoczne</string>
+    <string name="command_description_ignore_user">Ignoruje użytkownika, ukrywając dla Ciebie jego wiadomości</string>
+    <string name="jitsi_leave_conf_to_join_another_one_content">Opuścić obecną konferencję i przejść do innej\?</string>
+    <string name="error_jitsi_join_conf">Wystąpił błąd podczas próby dołączenia do konferencji</string>
+    <string name="directory_add_a_new_server_error_already_added">Ten serwer znajduje się już na liście</string>
+    <string name="directory_add_a_new_server_error">Nie można odnaleźć tego serwera lub jego listy pokoi</string>
+    <string name="directory_add_a_new_server_prompt">Wprowadź nazwę nowego serwera, który chcesz odkrywać.</string>
+    <string name="directory_add_a_new_server">Dodaj nowy serwer</string>
+    <string name="directory_your_server">Twój serwer</string>
+    <string name="room_settings_room_version_title">Wersja pokoju</string>
+    <string name="other_spaces_or_rooms_you_might_not_know">Inne przestrzenie lub pokoje, których możesz nie znać</string>
+    <string name="space_you_know_that_contains_this_room">Przestrzeń, o której wiesz, że zawiera ten pokój</string>
+    <string name="decide_who_can_find_and_join">Zdecyduj kto może odnaleźć i dołączyć do tego pokoju.</string>
+    <string name="tap_to_edit_spaces">Dotknij, aby edytować przestrzenie</string>
+    <string name="select_spaces">Wybierz przestrzenie</string>
+    <string name="decide_which_spaces_can_access">Zdecyduj które przestrzenie mogą mieć dostęp do tego pokoju. Członkowie wybranej przestrzeni będą mogli odnaleźć i dołączyć do nazwy pokoju.</string>
+    <string name="spaces_which_can_access">Przestrzenie mogące uzyskać dostęp</string>
+    <string name="allow_space_member_to_find_and_access">Zezwól użytkownikom przestrzeni na znalezienie i dostęp.</string>
+    <string name="settings_room_upgrades">Ulepszenia pokoju</string>
+    <string name="space_participants_kick_prompt_msg">wyproszenie użytkownika zaskutkuje usunięciem go z tej przestrzeni.
+\n
+\nAby uniemożliwić mu ponowne dołączenie, należy go zbanować.</string>
+    <string name="settings_room_directory_show_all_rooms_summary">Pokaż wszystkie pokoje w katalogu pokoi (również te zawierające treści dla dorosłych).</string>
+    <string name="settings_room_directory_show_all_rooms">Pokaż pokoje z treścią dla dorosłych</string>
+    <string name="notice_room_canonical_alias_alternative_changed">%1$s zmienił(a) alternatywne adresy dla tego pokoju.</string>
+    <string name="notice_room_aliases_added_and_removed_by_you">Dodano %1$s i usunięto %2$s jako adresy tego pokoju.</string>
+    <string name="notice_room_aliases_added_and_removed">%1$s dodał(a) %2$s i usunął(eła) %3$s jako adres tego pokoju.</string>
+    <string name="notice_room_withdraw_with_reason_by_you">Odrzucono zaproszenie od %1$s. Powód: %2$s</string>
+    <string name="notice_room_withdraw_with_reason">%1$s odrzucił(a) zaproszenie %2$s. Powód: %3$s</string>
+    <string name="a11y_delete_recorded_voice_message">Usuń nagranie</string>
+    <string name="feedback">Opinie</string>
+    <string name="bootstrap_crosssigning_progress_save_ssk">Synchronizacja klucza samopodpisującego (Self Signing key)</string>
+    <string name="cross_signing_verify_by_text">Weryfikacja ręczna poprzez tekst</string>
+    <string name="or_other_mx_capabale_client">lub innego klienta Matrix z krzyżową weryfikacją nowych sesji logowania</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-pt-rBR/strings.xml b/vector/src/main/res/values-pt-rBR/strings.xml
index 1d88792413..6220360aa8 100644
--- a/vector/src/main/res/values-pt-rBR/strings.xml
+++ b/vector/src/main/res/values-pt-rBR/strings.xml
@@ -124,22 +124,23 @@
     <string name="notice_power_level_changed_by_you">Você mudou o nível de poder de %1$s.</string>
     <string name="notice_power_level_changed">%1$s mudou o nível de poder de %2$s.</string>
     <string name="notice_power_level_diff">%1$s de %2$s para %3$s</string>
-    <string name="initial_sync_start_importing_account">Sinc Inicial:
+    <string name="initial_sync_start_importing_account">Sinc inicial:
 \nImportando conta…</string>
-    <string name="initial_sync_start_importing_account_crypto">Sinc Inicial:
+    <string name="initial_sync_start_importing_account_crypto">Sinc inicial:
 \nImportando crypto</string>
-    <string name="initial_sync_start_importing_account_rooms">Sinc Inicial:
+    <string name="initial_sync_start_importing_account_rooms">Sinc inicial:
 \nImportando Salas</string>
-    <string name="initial_sync_start_importing_account_joined_rooms">Sinc Inicial:
-\nImportando Salas Que Você Se Juntou</string>
-    <string name="initial_sync_start_importing_account_invited_rooms">Sinc Inicial:
-\nImportando Salas Que Você Foi Convidada(o)</string>
-    <string name="initial_sync_start_importing_account_left_rooms">Sinc Inicial:
-\nImportando Salas de Que Você Saiu</string>
-    <string name="initial_sync_start_importing_account_groups">Sinc Inicial:
-\nImportando Comunidades</string>
-    <string name="initial_sync_start_importing_account_data">Sinc Inicial:
-\nImportando Dados de Conta</string>
+    <string name="initial_sync_start_importing_account_joined_rooms">Sinc inicial:
+\nCarregando suas conversas
+\nSe você tem se juntado a um monte de salas, isto poderia levar um momento</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Sinc inicial:
+\nImportando salas convidadas</string>
+    <string name="initial_sync_start_importing_account_left_rooms">Sinc inicial:
+\nImportando salas saídas</string>
+    <string name="initial_sync_start_importing_account_groups">Sinc inicial:
+\nImportando comunidades</string>
+    <string name="initial_sync_start_importing_account_data">Sinc inicial:
+\nImportando dados de conta</string>
     <string name="event_status_sending_message">Enviando mensagem…</string>
     <string name="clear_timeline_send_queue">Limpar fila de envio</string>
     <string name="notice_room_invite_no_invitee_with_reason">Convite de %1$s. Razão: %2$s</string>
@@ -2697,9 +2698,9 @@
     <string name="settings_category_room_directory">Diretório de salas</string>
     <string name="dialog_edit_hint">Novo valor</string>
     <string name="action_switch">Alterar</string>
-    <string name="initial_sync_start_downloading">Sinc Inicial:
+    <string name="initial_sync_start_downloading">Sinc inicial:
 \nFazendo download de dados…</string>
-    <string name="initial_sync_start_server_computing">Sinc Inicial:
+    <string name="initial_sync_start_server_computing">Sinc inicial:
 \nEsperando por resposta de servidor…</string>
     <string name="a11y_trust_level_trusted">Nível de confiança confiado</string>
     <string name="a11y_trust_level_warning">Nível de confiança alerta</string>
@@ -3075,4 +3076,7 @@
     <string name="a11y_presence_unavailable">Indisponível</string>
     <string name="a11y_presence_offline">Offline</string>
     <string name="a11y_presence_online">Online</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Escolher servidorcasa</string>
+    <string name="login_error_homeserver_from_url_not_found">Não dá para alcançar um servidorcasa na URL %s. Por favor cheque seu link ou escolha um servidorcasa manualmente.</string>
+    <string name="notification_listening_for_notifications">À escuta por notificações</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-ro/strings.xml b/vector/src/main/res/values-ro/strings.xml
index 1c45088417..464a590f62 100644
--- a/vector/src/main/res/values-ro/strings.xml
+++ b/vector/src/main/res/values-ro/strings.xml
@@ -354,11 +354,12 @@
     <string name="initial_sync_start_importing_account_invited_rooms">Sincronizare inițială:
 \nSe importă camerele la care a-ți primit invitații</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Sincronizare inițială:
-\nSe importă camerele la care v-ați alăturat</string>
+\nSe încarcă conversațiile tale
+\nDacă te-ai alăturat mai multe camere, ar putea dura puțin mai mult</string>
     <string name="initial_sync_start_importing_account_rooms">Sincronizare inițială:
 \nSe importa camerele</string>
     <string name="initial_sync_start_importing_account_crypto">Sincronizare inițială:
-\nSe importă crypto</string>
+\nSe importă datele criptografice</string>
     <string name="initial_sync_start_importing_account">Sincronizare inițială:
 \nSe importă contul…</string>
     <string name="initial_sync_start_downloading">Sincronizare inițială:
@@ -393,4 +394,111 @@
     <string name="notice_room_server_acl_updated_ip_literals_allowed">Acum sunt permise serverele ce au adrese IP ce se potrivesc.</string>
     <string name="notice_room_server_acl_set_ip_literals_not_allowed">Sunt blocate serverele ce au adrese IP ce se potrivesc.</string>
     <string name="notice_room_server_acl_set_ip_literals_allowed">Sunt permise serverele ce au adrese IP ce se potrivesc.</string>
+    <string name="sign_out_bottom_sheet_backing_up_keys">Se creează o copie a cheilor criptografice.…</string>
+    <string name="sign_out_bottom_sheet_warning_no_backup">Dacă vă deconectați acum, veți pierde mesajele criptate</string>
+    <string name="keys_backup_is_not_finished_please_wait">Copierea cheilor nu sa încheiat, vă rugăm așteptați…</string>
+    <string name="title_activity_keys_backup_restore">Folosește cheia de rezervă</string>
+    <string name="title_activity_keys_backup_setup">Copia cheii de criptare</string>
+    <string name="title_activity_group_details">Detalii despre comunitate</string>
+    <string name="title_activity_bug_report">Raport de erori</string>
+    <string name="title_activity_historical">Istoricul activitățiilor</string>
+    <string name="title_activity_member_details">Detalii despre membri</string>
+    <string name="backup">Backup</string>
+    <string name="are_you_sure">Ești sigur \?</string>
+    <string name="keys_backup_activate">Folosește backup-ul cheii de criptare</string>
+    <string name="sign_out_bottom_sheet_warning_backup_not_active">Backup-ul cheii de criptare ar trebui să fie activ pe toate dispozitivele tale, pentru a evita pierderea mesajelor tale criptate.</string>
+    <string name="sign_out_bottom_sheet_warning_backing_up">Se creează backup-ul cheii de criptare. Daca te deconectezi de la aplicație acum vei pierde accesul la mesajele tale criptate.</string>
+    <string name="notification_listening_for_notifications">Se ascultă notificările</string>
+    <string name="system_theme">Setările implicite ale sistemului</string>
+    <string name="notice_end_to_end_unknown_algorithm_by_you">Tu ai pornit criptarea end-to-end (algoritm nerecunoscut %1$s).</string>
+    <string name="notice_end_to_end_unknown_algorithm">%1$s a pornit criptarea end-to-end (algoritm nerecunoscut %2$s).</string>
+    <string name="notice_end_to_end_ok_by_you">Tu ai pornit criptarea end-to-end.</string>
+    <string name="notice_end_to_end_ok">%1$s a pornit criptarea end-to-end.</string>
+    <string name="notice_direct_room_guest_access_forbidden_by_you">Tu ai împiedicat invitați din a se alătura acestei camere.</string>
+    <string name="notice_direct_room_guest_access_forbidden">%1$s a împiedicat invitații din a se alătura acestei camere.</string>
+    <string name="notice_room_guest_access_forbidden_by_you">Tu ai împiedicat invitați să se alăture acestei camere.</string>
+    <string name="notice_room_guest_access_forbidden">%1$s a împiedicat invitații din a se alătura acestei camere.</string>
+    <string name="notice_direct_room_guest_access_can_join_by_you">Tu ai permis invitațiilor să se alăture aici.</string>
+    <string name="notice_direct_room_guest_access_can_join">%1$s a permis invitațiilor să se alăture aici.</string>
+    <string name="notice_room_guest_access_can_join_by_you">Ai permis invitaților să se alăture acestei camere.</string>
+    <string name="notice_room_guest_access_can_join">%1$s a permis invitațiilor să se alăture acestei camere.</string>
+    <string name="notice_room_canonical_alias_no_change_by_you">Ai schimbat adresele pentru această cameră.</string>
+    <string name="notice_room_canonical_alias_no_change">%1$s a schimbat adresele pentru aceasta cameră.</string>
+    <string name="notice_room_canonical_alias_main_and_alternative_changed_by_you">Ai schimbat adresele principală și alternativă pentru această cameră.</string>
+    <string name="notice_room_canonical_alias_main_and_alternative_changed">%1$s a schimbat adresele principală și secundară pentru această cameră.</string>
+    <string name="notice_room_canonical_alias_alternative_changed_by_you">Ai schimbat adresele alternative pentru această cameră.</string>
+    <string name="notice_room_canonical_alias_alternative_changed">%1$s a modificat adresele alternative pentru această cameră.</string>
+    <plurals name="notice_room_canonical_alias_alternative_removed_by_you">
+        <item quantity="one">Ai șters adresa alternativă %1$s pentru aceasta cameră.</item>
+        <item quantity="few">Ai șters adresele alternative %1$s pentru aceste camere.</item>
+        <item quantity="other">Ai șters adresele alternative %1$s pentru aceste camere.</item>
+    </plurals>
+    <plurals name="notice_room_canonical_alias_alternative_removed">
+        <item quantity="one">%1$s a șters adresa alternativă %2$s pentru această cameră.</item>
+        <item quantity="few">%1$s a șters adresele alternative %2$s pentru această cameră.</item>
+        <item quantity="other">%1$s a șters adresele alternative %2$s pentru această cameră.</item>
+    </plurals>
+    <plurals name="notice_room_canonical_alias_alternative_added_by_you">
+        <item quantity="one">Ai adăugat adresa alternativă %1$spentru această cameră.</item>
+        <item quantity="few">Ai adăugat adresele alternative %1$s pentru această cameră.</item>
+        <item quantity="other">Ai adăugat adresele alternative %1$s pentru această cameră.</item>
+    </plurals>
+    <plurals name="notice_room_canonical_alias_alternative_added">
+        <item quantity="one">%1$s a adăugat adresa alternativă %2$s pentru aceasta cameră.</item>
+        <item quantity="few">%1$s a adăugat adresele alternative %2$s pentru această cameră.</item>
+        <item quantity="other">%1$s a adăugat adresele alternative %2$s pentru această cameră.</item>
+    </plurals>
+    <string name="notice_room_canonical_alias_unset_by_you">Ai șters adresa principală pentru această cameră.</string>
+    <string name="notice_room_canonical_alias_unset">%1$s a șters adresa principală pentru această cameră.</string>
+    <string name="notice_room_canonical_alias_set_by_you">Ai setat adresa principală pentru această cameră ca fiind %1$s.</string>
+    <string name="notice_room_canonical_alias_set">%1$s a setat adresa principală pentru această adresa ca fiind %2$s.</string>
+    <string name="notice_room_aliases_added_and_removed_by_you">Ai adăugat %1$s și îndepărtat %2$s ca adrese pentru această cameră.</string>
+    <string name="notice_room_aliases_added_and_removed">%1$s a adăugat %2$s și îndepărtat %3$s ca adrese pentru această cameră.</string>
+    <plurals name="notice_room_aliases_removed_by_you">
+        <item quantity="one">Ai îndepărtat %1$s ca adresă pentru această adresă.</item>
+        <item quantity="few">Ai îndepărtat %1$s ca adrese pentru această adresă.</item>
+        <item quantity="other">Ai îndepărtat %1$s ca adrese pentru această adresă.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_removed">
+        <item quantity="one">%1$s a retras %2$s ca o adresă pentru această cameră.</item>
+        <item quantity="few">%1$s a retras %2$s ca adrese pentru această cameră.</item>
+        <item quantity="other">%1$s a retras %2$s ca adrese pentru această cameră.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_added_by_you">
+        <item quantity="one">Ai adăugat %1$s ca o adresă pentru această cameră.</item>
+        <item quantity="few">Ai adăugat %1$s ca adrese pentru această cameră.</item>
+        <item quantity="other">Ai adăugat %1$s ca adrese pentru această cameră.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_added">
+        <item quantity="one">%1$s a adăugat pe %2$s ca o adresă pentru această cameră.</item>
+        <item quantity="few">%1$s a adăugat pe %2$s ca adrese pentru această cameră.</item>
+        <item quantity="other">%1$s a adăugat pe %2$s ca adrese pentru această cameră.</item>
+    </plurals>
+    <string name="notice_room_withdraw_with_reason_by_you">Ți-ai retras invitația către %1$s. Motivul: %2$s</string>
+    <string name="notice_room_withdraw_with_reason">%1$s și-a retras invitația către %2$s. Motivul: %3$s</string>
+    <string name="notice_room_kick_with_reason">%1$s la evacuat pe %2$s. Motivul: %3$s</string>
+    <string name="notice_room_invite_with_reason_by_you">Tu ai invitat %1$s. Motivul: %2$s</string>
+    <string name="notice_room_third_party_registered_invite_with_reason_by_you">Ai acceptat invitaţia pentru %1$s. Motivul: %2$s</string>
+    <string name="notice_room_third_party_registered_invite_with_reason">%1$s a acceptat invitaţia pentru %2$s. Motivul: %3$s</string>
+    <string name="notice_room_third_party_revoked_invite_with_reason_by_you">Ai retras invitaţia către %1$s de alăturare acestei camere. Motivul: %2$s</string>
+    <string name="notice_room_third_party_revoked_invite_with_reason">%1$s a retras invitaţia către %2$s de alăturare acestei camere. Motivul: %3$s</string>
+    <string name="notice_room_third_party_invite_with_reason_by_you">Tu ai trimis o invitaţie către %1$s pentru a se al\\ătura camerei. Motivul: %2$s</string>
+    <string name="notice_room_third_party_invite_with_reason">%1$s a trimis o invitaţie către %2$s pentru a se alătura camerei. Motivul: %3$s</string>
+    <string name="notice_room_ban_with_reason_by_you">Ai blocat utilizatorul %1$s. Motivul: %2$s</string>
+    <string name="notice_room_ban_with_reason">%1$s a blocat utilizatorul %2$s. Motivul: %3$s</string>
+    <string name="notice_room_unban_with_reason_by_you">Ai deblocat utilizatorul %1$s. Motivul: %2$s</string>
+    <string name="notice_room_unban_with_reason">%1$s a blocat pe %2$s. Motivul: %3$s</string>
+    <string name="notice_room_kick_with_reason_by_you">Ai dat afară utilizatorul %1$s. Motivul: %2$s</string>
+    <string name="notice_room_reject_with_reason_by_you">Ai respins invitaţia. Motivul: %1$s</string>
+    <string name="notice_room_reject_with_reason">%1$s a respins invitaţia. Motivul: %2$s</string>
+    <string name="notice_direct_room_leave_with_reason_by_you">Ai ieşit. Motivul: %1$s</string>
+    <string name="notice_direct_room_leave_with_reason">%1$s a părăsit camera. Motivul: %2$s</string>
+    <string name="notice_room_leave_with_reason_by_you">Ai părăsit camera. Motivul: %1$s</string>
+    <string name="notice_room_leave_with_reason">%1$s a părăsit camera. Motivul: %2$s</string>
+    <string name="notice_direct_room_join_with_reason_by_you">Tu te-ai alăturat. Motivul: %1$s</string>
+    <string name="notice_direct_room_join_with_reason">%1$s s-a alăturat. Motivul: %2$s</string>
+    <string name="notice_room_join_with_reason_by_you">Tu te-ai alăturat camerei. Motivul: %1$s</string>
+    <string name="notice_room_join_with_reason">%1$s s-a alăturat camerei. Motivul: %2$s</string>
+    <string name="notice_room_invite_you_with_reason">%1$s te-a invitat. Motivul: %2$s</string>
+    <string name="notice_room_invite_with_reason">%1$s la invitat pe %2$s. Motivul este: %3$s</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-ru/strings.xml b/vector/src/main/res/values-ru/strings.xml
index d497a94b3a..bc3751d351 100644
--- a/vector/src/main/res/values-ru/strings.xml
+++ b/vector/src/main/res/values-ru/strings.xml
@@ -1120,7 +1120,7 @@
     <string name="room_tombstone_continuation_link">Этот разговор продолжается здесь</string>
     <string name="room_tombstone_continuation_description">Эта комната является продолжением другого разговора</string>
     <string name="room_tombstone_predecessor_link">Нажмите здесь для просмотра старых сообщений</string>
-    <string name="command_description_join_room">Присоединиться к комнате с указанным псевдонимом</string>
+    <string name="command_description_join_room">Присоединиться к комнате с указанным адресом</string>
     <string name="command_description_clear_scalar_token">Для исправления управления приложениями Matrix</string>
     <string name="missing_permissions_error">Из-за отсутствия разрешений это действие невозможно.</string>
     <plurals name="format_time_s">
diff --git a/vector/src/main/res/values-sq/strings.xml b/vector/src/main/res/values-sq/strings.xml
index 30d67a5f1a..a89c081ba0 100644
--- a/vector/src/main/res/values-sq/strings.xml
+++ b/vector/src/main/res/values-sq/strings.xml
@@ -62,22 +62,23 @@
     <string name="notice_event_redacted_with_reason">Mesazh i hequr [arsye: %1$s]</string>
     <string name="notice_event_redacted_by_with_reason">Mesazh i hequr nga %1$s [arsye: %2$s]</string>
     <string name="notice_room_update">%s e përmirësoi këtë dhomë.</string>
-    <string name="initial_sync_start_importing_account">Njëkohësimi Fillestar:
+    <string name="initial_sync_start_importing_account">Njëkohësimi fillestar:
 \nPo importohet llogaria…</string>
-    <string name="initial_sync_start_importing_account_crypto">Njëkohësimi Fillestar:
+    <string name="initial_sync_start_importing_account_crypto">Njëkohësimi fillestar:
 \nPo importohet kriptografi</string>
-    <string name="initial_sync_start_importing_account_rooms">Njëkohësimi Fillestar:
+    <string name="initial_sync_start_importing_account_rooms">Njëkohësimi fillestar:
 \nPo importohen Dhoma</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Njëkohësimi Fillestar:
-\nPo importohen Dhoma Ku Është Bërë Hyrje</string>
-    <string name="initial_sync_start_importing_account_invited_rooms">Njëkohësimi Fillestar:
-\nPo importohen Dhoma Me Ftesë</string>
-    <string name="initial_sync_start_importing_account_left_rooms">Njëkohësimi Fillestar:
-\nPo importohen Dhoma të Braktisura</string>
-    <string name="initial_sync_start_importing_account_groups">Njëkohësimi Fillestar:
-\nPo importohen Bashkësi</string>
-    <string name="initial_sync_start_importing_account_data">Njëkohësimi Fillestar:
-\nPo importohet të Dhëna Llogarie</string>
+\nPo ngarkohen bisedat tuaja
+\nNëse keni hyrë në shumë dhoma, kjo mund të zgjasë ca</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Njëkohësimi fillestar:
+\nPo importohen dhoma me ftesë</string>
+    <string name="initial_sync_start_importing_account_left_rooms">Njëkohësimi fillestar:
+\nPo importohen dhoma të braktisura</string>
+    <string name="initial_sync_start_importing_account_groups">Njëkohësimi fillestar:
+\nPo importohen bashkësi</string>
+    <string name="initial_sync_start_importing_account_data">Njëkohësimi fillestar:
+\nPo importohet të dhëna llogarie</string>
     <string name="event_status_sending_message">Po dërgohet mesazh…</string>
     <string name="clear_timeline_send_queue">Spastro radhë pritjeje</string>
     <string name="notice_room_third_party_revoked_invite">%1$s shfuqizoi ftesën për %2$s për pjesëmarrje te dhoma</string>
@@ -289,7 +290,7 @@
     <string name="view_decrypted_source">Shihni Burim të Shfshehtëzuar</string>
     <string name="delete">Fshije</string>
     <string name="rename">Riemërtojeni</string>
-    <string name="report_content">Raportoni lëndë</string>
+    <string name="report_content">Raportoni Lëndë</string>
     <string name="active_call">Thirrje aktive</string>
     <string name="cannot_start_call">S’fillohet dot thirrja, ju lutemi, riprovoni më vonë</string>
     <string name="missing_permissions_title_to_start_conf_call">S’fillohet dot thirrja</string>
@@ -807,7 +808,7 @@
     <string name="command_description_ban_user">Dëbon përdoruesin me ID-në e dhënë</string>
     <string name="command_description_unban_user">I heq dëbimin përdoruesit me ID-në e dhënë</string>
     <string name="command_description_op_user">Përcaktoni shkallë pushteti të një përdoruesi</string>
-    <string name="command_description_join_room">Hyn në dhomë me aliasin e dhënë</string>
+    <string name="command_description_join_room">Hyn te dhoma me adresën e dhënë</string>
     <string name="command_description_part_room">Dilni nga dhoma</string>
     <string name="command_description_topic">Caktoni temë dhome</string>
     <string name="command_description_kick_user">Përzë përdoruesin me ID-në e dhënë</string>
@@ -2657,9 +2658,9 @@
     <string name="action_return">Kthehuni</string>
     <string name="action_switch">Ndërroje</string>
     <string name="event_status_sent_message">Mesazh i dërguar</string>
-    <string name="initial_sync_start_downloading">Njëkohësimi Fillestar:
+    <string name="initial_sync_start_downloading">Njëkohësimi fillestar:
 \nPo shkarkohen të dhëna…</string>
-    <string name="initial_sync_start_server_computing">Njëkohësimi Fillestar:
+    <string name="initial_sync_start_server_computing">Njëkohësimi fillestar:
 \nPo pritet për përgjigje nga shërbyesi…</string>
     <string name="spaces_beta_welcome_to_spaces_desc">Hapësirat janë mënyra për të grupuar dhoma dhe persona.</string>
     <string name="labs_use_restricted_join_rule_desc">Sinjalizimi lyp mbulim nga shërbyesi dhe version eksperimental dhome</string>
@@ -2846,13 +2847,13 @@
     <string name="voice_message_tap_to_stop_toast">Që ta ndalni ose ta dëgjoni, prekni mbi incizimin tuaj</string>
     <string name="voice_message_n_seconds_warning_toast">Edhe %1$ds</string>
     <string name="voice_message_release_to_send_toast">Mbajeni, që të incizojë, lëshojeni që të dërgohet</string>
-    <string name="a11y_delete_recorded_voice_message">Fshije mesazhin zanor të incizuar</string>
+    <string name="a11y_delete_recorded_voice_message">Fshije incizimin</string>
     <string name="a11y_recording_voice_message">Po incizohet mesazh zanor</string>
     <string name="a11y_pause_voice_message">Ndalni Mesazh Zanor</string>
     <string name="a11y_play_voice_message">Luani Mesazh Zanor</string>
     <string name="a11y_lock_voice_message">Kyçje Mesazhi Zanor</string>
     <string name="voice_message_slide_to_cancel">Rrëshqiteni që të anulohet</string>
-    <string name="a11y_start_voice_message">Nisni Mesazh Zanor</string>
+    <string name="a11y_start_voice_message">Incizoni Mesazh Zanor</string>
     <string name="allow_anyone_in_room_to_access">Lejo cilindo te %s ta gjejë dhe hyjë. Mund të përzgjidhni edhe hapësira të tjera.</string>
     <string name="upgrade_required">Lypset Domosdo Përmirësim</string>
     <string name="sent_a_voice_message">Zë</string>
@@ -2993,4 +2994,7 @@
     <string name="command_description_ignore_user">Shpërfill një përdorues, duke fshehur mesazhet e tij prej jush</string>
     <string name="a11y_presence_offline">Jo në linjë</string>
     <string name="a11y_presence_online">Në linjë</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Zgjidhni shërbyes Home</string>
+    <string name="login_error_homeserver_from_url_not_found">Te URL-ja %s s’kapet dot një shërbyes Home. Ju lutemi, kontrolloni lidhjen tuaj, ose zgjidheni një shërbyes Home dorazi.</string>
+    <string name="notification_listening_for_notifications">Po dëgjohet për njoftime</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-sv/strings.xml b/vector/src/main/res/values-sv/strings.xml
index a33f8a5080..8ed89e3ca7 100644
--- a/vector/src/main/res/values-sv/strings.xml
+++ b/vector/src/main/res/values-sv/strings.xml
@@ -123,7 +123,8 @@
     <string name="initial_sync_start_importing_account_rooms">Inledande synk:
 \nImporterar rum</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Inledande synk:
-\nImporterar anslutna rum</string>
+\nLaddar dina konversationer
+\nOm du har gått med i många rum så kan detta ta lite tid</string>
     <string name="initial_sync_start_importing_account_invited_rooms">Inledande synk:
 \nImporterar inbjudna rum</string>
     <string name="initial_sync_start_importing_account_left_rooms">Inledande synk:
@@ -2619,9 +2620,9 @@
     <string name="room_settings_room_version_title">Rumsversion</string>
     <string name="dialog_edit_hint">Nytt värde</string>
     <string name="action_switch">Byt</string>
-    <string name="initial_sync_start_downloading">Initial synk:
+    <string name="initial_sync_start_downloading">Inledande synk:
 \nLaddar ner data…</string>
-    <string name="initial_sync_start_server_computing">Initial synk:
+    <string name="initial_sync_start_server_computing">Inledande synk:
 \nVäntar på serversvar…</string>
     <string name="a11y_view_read_receipts">Visa läskvitton</string>
     <string name="a11y_rule_notify_off">Avisera inte</string>
@@ -3005,4 +3006,7 @@
     <string name="a11y_presence_unavailable">Otillgänglig</string>
     <string name="a11y_presence_offline">Offline</string>
     <string name="a11y_presence_online">Online</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">Välj hemserver</string>
+    <string name="login_error_homeserver_from_url_not_found">Kan inte nå en hemserver på URL:en %s. Vänligen kontrollera din länk eller välj en hemserver manuellt.</string>
+    <string name="notification_listening_for_notifications">Lyssnar efter aviseringar</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-uk/strings.xml b/vector/src/main/res/values-uk/strings.xml
index 3ffe746b9f..c31ff8515a 100644
--- a/vector/src/main/res/values-uk/strings.xml
+++ b/vector/src/main/res/values-uk/strings.xml
@@ -148,7 +148,8 @@
     <string name="initial_sync_start_importing_account_invited_rooms">Початкова синхронізація:
 \nІмпортування запрошень до кімнат</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Початкова синхронізація:
-\nІмпортування кімнат, до яких ви приєдналися</string>
+\nЗавантаження ваших бесід
+\nЯкщо ви приєдналися до багатьох кімнат, це може тривати досить довго</string>
     <string name="initial_sync_start_importing_account_rooms">Початкова синхронізація:
 \nІмпортування кімнат</string>
     <string name="initial_sync_start_importing_account_crypto">Початкова синхронізація:
@@ -764,7 +765,7 @@
     <string name="font_size">Розмір шрифту</string>
     <string name="tiny">Крихітний</string>
     <string name="small">Дрібний</string>
-    <string name="normal">Нормальний</string>
+    <string name="normal">Звичайний</string>
     <string name="large">Чималий</string>
     <string name="larger">Великий</string>
     <string name="largest">Найбільший</string>
@@ -834,7 +835,7 @@
     <string name="room_settings_mute">Без звуку</string>
     <string name="room_settings_add_homescreen_shortcut">Додати ярлик на головний екран</string>
     <string name="settings_notification_privacy">Приватність сповіщень</string>
-    <string name="settings_notification_privacy_normal">Нормальний</string>
+    <string name="settings_notification_privacy_normal">Звичайний</string>
     <string name="title_activity_choose_sticker">Надіслати наліпку</string>
     <string name="option_send_sticker">Надіслати наліпку</string>
     <string name="no_sticker_application_dialog_content">У вас поки що не має наліпок.
@@ -991,7 +992,7 @@
     <string name="command_description_op_user">Визначити рівень повноважень користувача</string>
     <string name="command_description_deop_user">Скинути рівень доступу користувача із вказаним ID</string>
     <string name="command_description_invite_user">Запросити користувача із вказаним ID до поточної кімнати</string>
-    <string name="command_description_join_room">Приєднатися до кімнати із вказаним псевдонімом</string>
+    <string name="command_description_join_room">Приєднує до кімнати із вказаною адресою</string>
     <string name="command_description_part_room">Вийти з кімнати</string>
     <string name="command_description_topic">Встановити тему кімнати</string>
     <string name="command_description_kick_user">Копнути користувача із вказаним ID</string>
@@ -1308,7 +1309,7 @@
     <string name="action_add">Додати</string>
     <string name="audio_video_meeting_description">Наради використовують політику безпеки та дозволів Jitsi. Усі люди, які зараз перебувають у кімнаті, побачать запрошення приєднатися під час вашої зустрічі.</string>
     <string name="start_chatting">Почати спілкування</string>
-    <string name="labs_show_unread_notifications_as_tab">Додати спеціальну вкладку для непрочитаних сповіщень на головному екрані.</string>
+    <string name="labs_show_unread_notifications_as_tab">Додати спеціальну вкладку для непрочитаних сповіщень на головний екран.</string>
     <string name="settings_labs_show_complete_history_in_encrypted_room">Показувати повну історію зашифрованих кімнат</string>
     <string name="settings_account_data">Дані облікового запису</string>
     <string name="settings_dev_tools">Інструменти розробника</string>
@@ -1463,7 +1464,7 @@
     <string name="room_alias_action_publish">Опублікувати цю адресу</string>
     <string name="room_alias_local_address_add">Додати локальну адресу</string>
     <string name="room_alias_local_address_empty">Кімната не має локальної адреси</string>
-    <string name="room_alias_local_address_subtitle">Встановіть адреси для цієї кімнати, щоб користувачі могли знаходити цю кімнату через ваш домашній сервер (%1$s)</string>
+    <string name="room_alias_local_address_subtitle">Укажіть адреси для цієї кімнати, щоб користувачі могли знаходити цю кімнату через ваш домашній сервер (%1$s)</string>
     <string name="room_alias_local_address_title">Локальні адреси</string>
     <string name="room_alias_address_hint">Нова опублікована адреса (наприклад, #alias:server)</string>
     <string name="room_alias_address_empty">Інших опублікованих адрес поки що немає.</string>
@@ -1476,7 +1477,7 @@
     <string name="room_alias_published_other">Інші опубліковані адреси:</string>
     <string name="room_alias_main_address_hint">Основна адреса</string>
     <string name="room_alias_published_alias_main">Це основна адреса</string>
-    <string name="room_alias_published_alias_subtitle">Загальнодоступні адреси може використовувати будь-хто на будь-якому сервері для приєднання до вашої кімнати. Щоб опублікувати адресу спочатку встановіть її локальною адресою.</string>
+    <string name="room_alias_published_alias_subtitle">Загальнодоступні адреси може використовувати будь-хто на будь-якому сервері для приєднання до вашої кімнати. Щоб опублікувати адресу спочатку вкажіть її локальною адресою.</string>
     <string name="room_alias_published_alias_title">Загальнодоступні адреси</string>
     <string name="room_alias_title">Адреси кімнат</string>
     <string name="room_settings_alias_subtitle">Перегляньте та керуйте адресами цієї кімнати та їхньою видимістю у каталозі кімнат.</string>
@@ -2860,4 +2861,21 @@
     <string name="bootstrap_dont_reuse_pwd">Не застосовуйте пароль облікового запису повторно.</string>
     <string name="bootstrap_info_confirm_text">Введіть %s ще раз, щоб підтвердити.</string>
     <string name="bootstrap_info_text">Захистіть та розблокуйте зашифровані повідомлення та перевіряйте довіреність за допомогою %s.</string>
+    <string name="identity_server_consent_dialog_neutral_policy">Політика</string>
+    <string name="command_description_unignore_user">Перестає нехтувати користувача, показує їхні подальші повідомлення</string>
+    <string name="command_description_ignore_user">Нехтує користувача, ховає їхні повідомлення від вас</string>
+    <string name="settings_discovery_hide_identity_server_policy_title">Сховати політику ідентифікації сервера</string>
+    <string name="settings_discovery_show_identity_server_policy_title">Показати політику ідентифікації сервера</string>
+    <string name="command_description_whois">Показує відомості про користувача</string>
+    <string name="command_description_avatar_for_room">Змінює ваш аватар лише у поточній кімнаті</string>
+    <string name="command_description_room_avatar">Змінює аватар поточної кімнати</string>
+    <string name="command_description_nick_for_room">Змінює ваше показуване ім\'я лише у поточній кімнаті</string>
+    <string name="command_description_room_name">Установлює назву кімнати</string>
+    <string name="settings_discovery_no_policy_provided">Сервер ідентифікації не надав жодних правил</string>
+    <string name="labs_use_restricted_join_rule_desc">Попередження: вимагає підтримки сервера та експериментальної версії кімнати</string>
+    <string name="spaces_feeling_experimental_subspace">Бажаєте поекспериментувати\?
+\nМожете додати наявні простори до простору.</string>
+    <string name="labs_use_restricted_join_rule">Експериментальний простір - обмежена кімната.</string>
+    <string name="all_rooms_youre_in_will_be_shown_in_home">Усі кімнати, у яких ви перебуваєте, буде показано на сторінці Домівка.</string>
+    <string name="preference_show_all_rooms_in_home">Показувати у Домівці</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-vi/strings.xml b/vector/src/main/res/values-vi/strings.xml
index dbc40bfc44..31b5c77e18 100644
--- a/vector/src/main/res/values-vi/strings.xml
+++ b/vector/src/main/res/values-vi/strings.xml
@@ -1543,4 +1543,106 @@
     <string name="audio_call_with_participant">Cuộc gọi âm thanh với %s</string>
     <string name="video_call_with_participant">Cuộc gọi video với %s</string>
     <string name="call_ringing">Cuộc gọi đang reo…</string>
+    <string name="room_settings_space_access_public_description">Ai có thể tìm và tham gia không gian</string>
+    <string name="room_settings_space_access_title">Truy cập không gian</string>
+    <string name="room_settings_access_rules_pref_dialog_title">Ai có quyền truy cập\?</string>
+    <string name="account_email_validation_error">Không thể hoàn thành xác nhận email. Vui lòng kiểm tra email của bạn và bấm vào đường liên kết trong đó. Một khi đã xong, bấm tiếp tục.</string>
+    <string name="account_email_validation_message">Vui lòng kiểm tra email và bấm vào liên kết trong đó. Một khi xong, bấm tiếp tục.</string>
+    <string name="settings_data_save_mode_summary">Chế độ tiết kiệm dữ liệu sẽ dừng việc đưa ra các thông báo đang có mặt và đang gõ.</string>
+    <string name="template_startup_notification_fdroid_battery_optim_message">${app_name} cần phải giữ kết nối mạng liên tục dưới nền để đạt hiệu quả thông báo cao nhất:
+\nỞ màn hình tiếp theo ban sẽ được hỏi để cho phép ${app_name} hoạt động liên tục dưới nền, hãy nhấn cho phép.</string>
+    <string name="template_startup_notification_privacy_message">${app_name} sẽ chạy dưới nền để quản lý các thông báo của bạn một cách chính xác và riêng tư. Điều này sẽ có thể ảnh hưởng đến thời lượng pin.</string>
+    <string name="startup_notification_privacy_title">Thông báo riêng tư</string>
+    <string name="settings_integrations_summary">Sử dụng trình quản lý chung để quản lý bot, các cầu nối, widget và các gói nhãn dán.
+\nTrình quản lý chung sẽ nhận được dữ liệu hiệu chỉnh, và sẽ có thể điều chỉnh các widget, gửi lời mời vào phòng và thiết lập các mốc quyền lợi theo ý bạn.</string>
+    <string name="template_settings_background_fdroid_sync_mode_real_time_description">${app_name} sẽ đồng bộ hóa dưới nền trong một khoảng thời gian nhất định (có thể điều chỉnh thời gian).
+\nViệc này sẽ làm ảnh hưởng tới khả năng thu phát và sử dụng pin, sẽ xuất hiện một thông báo cho biết lúc nào ${app_name} đang hoạt động.</string>
+    <string name="template_settings_background_fdroid_sync_mode_battery_description">${app_name} sẽ đồng bộ dưới nền và sẽ sử dụng các tài nguyên như pin một cách tiết kiệm.
+\nTùy vào các tài nguyên có sẵn trên thiết bị, việc đồng bộ hóa có thể sẽ bị ngăn cản bởi hệ điều hành.</string>
+    <string name="settings_troubleshoot_test_battery_failed">Nếu người dùng để thiết bị đã tháo sạc và đang chờ trong khoảng thời gian, với màn hình tắt, thiết bị sẽ khởi động chế độ Doze. Việc này ngăn cản các ứng dụng sử dụng mạng và dừng lại các hoạt động đồng bộ hóa, kể cả các báo thức.</string>
+    <string name="template_settings_troubleshoot_test_bg_restricted_failed">Giới hạn dưới nền đã được bật cho ${app_name}.
+\nCác hoạt động của ứng dụng sẽ bị giới hạn nặng nề khi chạy dưới nền, điều này có thể ảnh hưởng đến cách thông báo của ứng dụng.
+\n%1$s</string>
+    <string name="template_settings_troubleshoot_test_bg_restricted_success">Các giới hạn dưới nền đã được tắt cho ${app_name}. Bài kiểm tra này sẽ được chạy khi sử dụng dữ liệu di động (không Wi-Fi).
+\n%1$s</string>
+    <string name="settings_troubleshoot_test_bg_restricted_title">Kiểm tra giới hạn dưới nền</string>
+    <string name="settings_troubleshoot_test_service_boot_quickfix">Bật khởi động cùng hệ thống</string>
+    <string name="template_settings_troubleshoot_test_service_boot_failed">Dịch vụ sẽ không khởi động sau khi thiết bị đã khởi động lại, bạn sẽ không nhận được bất kỳ thông báo nào cho tới khi ${app_name} được mở một lần.</string>
+    <string name="settings_troubleshoot_test_service_boot_success">Dịch vụ sẽ bắt đầu ngay khi thiết bị được khởi động lại.</string>
+    <string name="settings_troubleshoot_test_service_boot_title">Khởi động cùng hệ thống</string>
+    <string name="settings_troubleshoot_test_service_restart_failed">Dịch vụ không thể khởi động</string>
+    <string name="settings_troubleshoot_test_service_restart_success">Dịch vụ đã bị đóng và tự động khởi động lại.</string>
+    <string name="settings_troubleshoot_test_service_restart_title">Tụ động khởi động lại dịch vụ thông báo</string>
+    <string name="settings_troubleshoot_test_foreground_service_started_quickfix">Bắt đầu</string>
+    <string name="settings_troubleshoot_test_foreground_service_started_failed">Dịch vụ thông báo đang không hoạt động:
+\nHãy thử khởi động lại ứng dụng.</string>
+    <string name="settings_troubleshoot_test_foreground_service_startedt_success">Dịch vụ thông báo đang chạy.</string>
+    <string name="settings_troubleshoot_test_foreground_service_started_title">Dịch vụ thông báo</string>
+    <string name="settings_troubleshoot_test_notification_notification_clicked">Thông báo đã được bấm!</string>
+    <string name="settings_troubleshoot_test_notification_notice">Hãy bấm vào thông báo. Nếu bạn không thấy bất kỳ thông báo nào, vui lòng kiểm tra cài đặt hệ thống.</string>
+    <string name="settings_troubleshoot_test_notification_title">Hiển thị thông báo</string>
+    <string name="settings_troubleshoot_test_push_notification_content">Bạn đang xem thông báo này! Bấm tôi đi!</string>
+    <string name="settings_troubleshoot_test_push_loop_failed">Đẩy không thành công. Giải pháp có thể là cài đặt lại ứng dụng.</string>
+    <string name="settings_troubleshoot_test_push_loop_success">Ứng dụng đang được ĐẨY</string>
+    <string name="settings_troubleshoot_test_push_loop_waiting_for_push">Ứng dụng đang chờ được ĐẨY</string>
+    <string name="settings_troubleshoot_test_push_loop_title">Đẩy thử</string>
+    <string name="settings_troubleshoot_test_token_registration_failed">Khai báo token FCM với máy chủ không thành công:
+\n%1$s</string>
+    <string name="settings_troubleshoot_test_token_registration_success">Đăng ký token FCM thành công tới máy chủ.</string>
+    <string name="settings_troubleshoot_test_token_registration_title">Đăng ký token</string>
+    <string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">Thêm tài khoản</string>
+    <string name="template_settings_troubleshoot_test_fcm_failed_account_missing">[%1$s
+\nLỗi này đã vượt khỏi tầm kiểm soát của ${app_name}. Không phát hiện thấy tài khoản Google trên thiết bị. Vui lòng thêm một tài khoản.</string>
+    <string name="template_settings_troubleshoot_test_fcm_failed_service_not_available">[%1$s
+\nLỗi này đã vượt ra khỏi tầm kiểm soát của ${app_name}. Nó có thể xảy ra vì vài lý do. Có thể nó sẽ hoạt động nếu bạn thử lại sau, bạn cũng có thể kiểm rằng các dịch vụ của Google Play không bị giới hạn quyền sử dụng data trong cài đặt hệ thống, hoặc đồng hồ trên thiết bị của bạn bị sai, hoặc là do bản ROM custom của bạn.</string>
+    <string name="template_settings_troubleshoot_test_fcm_failed_too_many_registration">[%1$s
+\nLỗi này đã vượt ra khỏi tầm kiểm soát của ${app_name} và theo như Google thông báo, lỗi này chỉ ra rằng thiết bị đã có quá nhiều ứng dụng được đăng ký với FCM. Lỗi này chỉ xảy ra khi có quá nhiều ứng dụng hoạt động, vì vậy có thể sẽ không ảnh hưởng đến trải nghiệm người dùng cơ bản.</string>
+    <string name="settings_troubleshoot_test_fcm_failed">Lấy token FCM thất bại:
+\n%1$s</string>
+    <string name="settings_troubleshoot_test_fcm_success">Lấy token FCM thành công:
+\n%1$s</string>
+    <string name="settings_troubleshoot_test_fcm_title">Token Firebase</string>
+    <string name="settings_troubleshoot_test_play_services_quickfix">Sửa dịch vụ của Google Play</string>
+    <string name="template_settings_troubleshoot_test_play_services_failed">${app_name} sử dụng Dịch vụ của Google Play nhằm đưa ra cái thông báo đẩy nhưng có vẻ nó đã không được căn chỉnh đúng cách:
+\n%1$s</string>
+    <string name="settings_troubleshoot_test_play_services_success">Dịch vụ của Google Play APK đang hoạt động và đã được nâng cấp lên phiên bản mới nhất.</string>
+    <string name="settings_troubleshoot_test_play_services_title">Kiểm tra dịch vụ của Google Play</string>
+    <string name="settings_troubleshoot_test_bing_settings_quickfix">Kiểm tra các cài đặt</string>
+    <string name="settings_troubleshoot_test_bing_settings_failed_to_load_rules">Không thể thiết lập các thay đổi nâng cao, vui lòng thử lại.</string>
+    <string name="settings_troubleshoot_test_bing_settings_failed">Bạn đã tắt một vài thông báo trong cài đặt nâng cao.</string>
+    <string name="settings_troubleshoot_test_bing_settings_success_with_warn">Một vài thông báo tin nhắn đã được thiết lập thành im lặng (sẽ thông báo nhưng không có âm thanh).</string>
+    <string name="settings_troubleshoot_diagnostic_failure_status_no_quickfix">Một hoặc nhiều phép thử đã thất bại, vui lòng gửi một bản báo cáo lỗi để giúp chúng tôi điều tra.</string>
+    <string name="settings_troubleshoot_diagnostic_failure_status_with_quickfix">Một hoặc nhiều phép thử đã thất bại, hãy thử (các) phương pháp được đề xuất sau.</string>
+    <string name="settings_troubleshoot_diagnostic_success_status">Kết quả phân tích cơ bản là OK. Nếu bạn vẫn không thể nhận thông báo, vui lòng gửi cho chúng tôi một bản báo cáo lỗi để giúp chúng tôi điều tra.</string>
+    <string name="settings_troubleshoot_diagnostic_running_status">Đang chạy… (%1$d of %2$d)</string>
+    <string name="settings_troubleshoot_diagnostic_run_button_title">Chạy thử</string>
+    <string name="settings_troubleshoot_diagnostic">Chuẩn đoán khắc phục sự cố</string>
+    <string name="settings_notification_emails_enable_for_email">Bật thông báo qua email cho %s</string>
+    <string name="settings_notification_emails_no_emails">Để được nhận thông báo qua email, hãy liên kết một địa chỉ mail với tài khoản Matrix của bạn</string>
+    <string name="settings_notification_emails_category">Thông báo qua email</string>
+    <string name="malformed_id">ID không hợp lệ. ID hợp lệ có thể là một địa chỉ email hoặc một ID Matrix như \'@localpart:domain\'</string>
+    <string name="room_permissions_upgrade_the_space">Nâng cấp không gian</string>
+    <string name="room_permissions_change_space_name">Thay đổi tên không gian</string>
+    <string name="room_permissions_enable_space_encryption">Bật mã hóa không gian</string>
+    <string name="room_permissions_change_main_address_for_the_space">Đổi địa chỉ chính cho không gian</string>
+    <string name="room_permissions_change_space_avatar">Đổi ảnh đại diện của không gian</string>
+    <string name="space_permissions_notice_read_only">Bạn không có quyền thay đổi các vai trò cần thiết để thay đổi các phần trong không gian này</string>
+    <string name="space_permissions_notice">Chọn các vai trò cần thiết để thay đổi các phần của không gian này</string>
+    <string name="space_settings_permissions_subtitle">Xem và cập nhật các vai trò cần thiết để thay đổi các phần trong không gian.</string>
+    <string name="room_settings_permissions_subtitle">Xem và cập nhật các vai trò cần thiết khi thay đổi các phần trong phòng.</string>
+    <string name="space_settings_permissions_title">Các quyền trong không gian</string>
+    <string name="room_settings_permissions_title">Các quyền trong phòng</string>
+    <string name="ssl_only_accept">Chỉ chấp nhận sử dụng chứng chỉ nếu quản trị viên máy chủ đã đăng tải một dấu vân tay trùng khớp với dấu ở trên.</string>
+    <string name="ssl_expected_existing_expl">Chứng chỉ này đã thay đổi từ một chứng chỉ được tin cậy trước đây sang một chứng chỉ không được tin cậy. Phía máy chủ có thể đã làm mới chứng chỉ. Liên hệ quản trị viên của máy chủ để được cấp dấu vân tay.</string>
+    <string name="ssl_unexpected_existing_expl">Chứng chỉ đã bị thay đổi từ một thiết bị được tin cậy của bạn. Điều này RẤT BẤT THƯỜNG. Chúng tôi khuyên bạn KHÔNG NÊN CHẤP NHẬN chứng chỉ mới này.</string>
+    <string name="ssl_cert_new_account_expl">Nếu quản trị viên của máy chủ đã nói rằng điều này có thể xảy ra, hãy chắc chắn rằng dấu vân tay phía dưới trùng với dấu vân tay được họ cung cấp.</string>
+    <string name="space_participants_unban_prompt_msg">Hủy cấm người dùng sẽ cho phép họ tham gia không gian này lần nữa.</string>
+    <string name="space_participants_ban_prompt_msg">Cấm người dùng này sẽ đá họ khỏi không gian này và ngăn chặn họ tiếp tục tham gia.</string>
+    <string name="space_participants_kick_prompt_msg">hành động của bạn sẽ xóa họ khỏi không gian này.
+\n
+\nTrong trường hợp không muốn họ quay lại, bạn nên cấm họ tham gia lần nữa.</string>
+    <string name="room_settings_addresses_invalid_format_dialog_body">\'%s\' không phải là định dạng phù hợp</string>
+    <string name="room_settings_addresses_invalid_format_dialog_title">Định dạng không phù hợp</string>
+    <string name="room_settings_invalid_group_format_dialog_body">\'%s\' không phải là một ID cộng đồng hợp lệ</string>
+    <string name="room_settings_invalid_group_format_dialog_title">ID cộng đồng không hợp lệ</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-zh-rCN/strings.xml b/vector/src/main/res/values-zh-rCN/strings.xml
index 039bc6d5d8..4729586562 100644
--- a/vector/src/main/res/values-zh-rCN/strings.xml
+++ b/vector/src/main/res/values-zh-rCN/strings.xml
@@ -67,13 +67,14 @@
     <string name="initial_sync_start_importing_account_rooms">初始化同步:
 \n正在导入聊天室</string>
     <string name="initial_sync_start_importing_account_joined_rooms">初始化同步:
-\n正在导入已加入的聊天室</string>
+\n正在加载对话
+\n如果你加入了很多论聊天室,这可能需要一段时间</string>
     <string name="initial_sync_start_importing_account_invited_rooms">初始化同步:
 \n正在导入已邀请的聊天室</string>
     <string name="initial_sync_start_importing_account_left_rooms">初始化同步:
 \n正在导入已离开的聊天室</string>
     <string name="initial_sync_start_importing_account_groups">初始化同步:
-\n正在导入社群</string>
+\n正在导入社区</string>
     <string name="initial_sync_start_importing_account_data">初始化同步:
 \n正在导入账号数据</string>
     <string name="notice_room_update">%s 升级了此聊天室。</string>
@@ -2959,4 +2960,7 @@
     <string name="a11y_presence_unavailable">不可用</string>
     <string name="a11y_presence_offline">离线</string>
     <string name="a11y_presence_online">在线</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">选择主服务器</string>
+    <string name="login_error_homeserver_from_url_not_found">无法访问 URL %s 上的主服务器。请检查您的链接或手动选择一个主服务器。</string>
+    <string name="notification_listening_for_notifications">侦听通知</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values-zh-rTW/strings.xml b/vector/src/main/res/values-zh-rTW/strings.xml
index 3fc79ecf34..0445264606 100644
--- a/vector/src/main/res/values-zh-rTW/strings.xml
+++ b/vector/src/main/res/values-zh-rTW/strings.xml
@@ -67,7 +67,8 @@
     <string name="initial_sync_start_importing_account_rooms">初始化同步:
 \n正在匯入聊天室</string>
     <string name="initial_sync_start_importing_account_joined_rooms">初始化同步:
-\n正在匯入已加入的聊天室</string>
+\n正在載入您的對話
+\n若您加入了很多聊天室,這可能會花一點時間</string>
     <string name="initial_sync_start_importing_account_invited_rooms">初始化同步:
 \n正在匯入已邀請的聊天室</string>
     <string name="initial_sync_start_importing_account_left_rooms">初始化同步:
@@ -2949,4 +2950,7 @@
     <string name="a11y_presence_unavailable">不可用</string>
     <string name="a11y_presence_offline">離線</string>
     <string name="a11y_presence_online">線上</string>
+    <string name="login_error_homeserver_from_url_not_found_enter_manual">選擇家伺服器</string>
+    <string name="login_error_homeserver_from_url_not_found">無法存取 URL %s 的家伺服器。請檢查您的連結或手動選擇家伺服器。</string>
+    <string name="notification_listening_for_notifications">監聽通知</string>
 </resources>
\ No newline at end of file
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 9f7ba419be..faa5d107bf 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -197,16 +197,16 @@
     <string name="room_displayname_empty_room">Empty room</string>
     <string name="room_displayname_empty_room_was">Empty room (was %s)</string>
 
-    <string name="initial_sync_start_server_computing">Initial Sync:\nWaiting for server response…</string>
-    <string name="initial_sync_start_downloading">Initial Sync:\nDownloading data…</string>
-    <string name="initial_sync_start_importing_account">Initial Sync:\nImporting account…</string>
-    <string name="initial_sync_start_importing_account_crypto">Initial Sync:\nImporting crypto</string>
-    <string name="initial_sync_start_importing_account_rooms">Initial Sync:\nImporting Rooms</string>
-    <string name="initial_sync_start_importing_account_joined_rooms">Initial Sync:\nImporting Joined Rooms</string>
-    <string name="initial_sync_start_importing_account_invited_rooms">Initial Sync:\nImporting Invited Rooms</string>
-    <string name="initial_sync_start_importing_account_left_rooms">Initial Sync:\nImporting Left Rooms</string>
-    <string name="initial_sync_start_importing_account_groups">Initial Sync:\nImporting Communities</string>
-    <string name="initial_sync_start_importing_account_data">Initial Sync:\nImporting Account Data</string>
+    <string name="initial_sync_start_server_computing">Initial sync:\nWaiting for server response…</string>
+    <string name="initial_sync_start_downloading">Initial sync:\nDownloading data…</string>
+    <string name="initial_sync_start_importing_account">Initial sync:\nImporting account…</string>
+    <string name="initial_sync_start_importing_account_crypto">Initial sync:\nImporting crypto</string>
+    <string name="initial_sync_start_importing_account_rooms">Initial sync:\nImporting rooms</string>
+    <string name="initial_sync_start_importing_account_joined_rooms">Initial sync:\nLoading your conversations\nIf you\'ve joined lots of rooms, this might take a while</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Initial sync:\nImporting invited rooms</string>
+    <string name="initial_sync_start_importing_account_left_rooms">Initial sync:\nImporting left rooms</string>
+    <string name="initial_sync_start_importing_account_groups">Initial sync:\nImporting communities</string>
+    <string name="initial_sync_start_importing_account_data">Initial sync:\nImporting account data</string>
 
 
     <string name="event_status_sent_message">Message sent</string>
@@ -322,6 +322,7 @@
     <string name="notification_sync_init">Initializing service</string>
     <string name="notification_sync_in_progress">Synchronising…</string>
     <string name="notification_listening_for_events">Listening for events</string>
+    <string name="notification_listening_for_notifications">Listening for notifications</string>
     <string name="notification_noisy_notifications">Noisy notifications</string>
     <string name="notification_silent_notifications">Silent notifications</string>
 
@@ -1079,6 +1080,9 @@
     <string name="room_settings_forget">Forget</string>
     <string name="room_settings_add_homescreen_shortcut">Add to Home screen</string>
 
+    <string name="shortcut_disabled_reason_room_left">The room has been left!</string>
+    <string name="shortcut_disabled_reason_sign_out">The session has been signed out!</string>
+
     <!-- home sliding menu -->
     <string name="room_sliding_menu_messages">Messages</string>
     <string name="room_sliding_menu_settings">Settings</string>
@@ -2365,11 +2369,14 @@
     <string name="settings_discovery_consent_title">Send emails and phone numbers</string>
     <string name="settings_discovery_consent_notice_on">You have given your consent to send emails and phone numbers to this identity server to discover other users from your contacts.</string>
     <string name="settings_discovery_consent_notice_off">You have not given your consent to send emails and phone numbers to this identity server to discover other users from your contacts.</string>
+    <string name="settings_discovery_consent_notice_off_2">Your contacts are private. To discover users from your contacts, we need your permission to send contact info to your identity server.</string>
     <string name="settings_discovery_consent_action_revoke">Revoke my consent</string>
     <string name="settings_discovery_consent_action_give_consent">Give consent</string>
 
     <string name="identity_server_consent_dialog_title">Send emails and phone numbers</string>
+    <string name="identity_server_consent_dialog_title_2">Send emails and phone numbers to %s</string>
     <string name="identity_server_consent_dialog_content">In order to discover existing contacts you know, do you accept to send your contact data (phone numbers and/or emails) to the configured identity server (%1$s)?\n\nFor more privacy, the sent data will be hashed before being sent.</string>
+    <string name="identity_server_consent_dialog_content_2">To discover existing contacts, you need to send contact info to your identity server.\n\nWe hash your data before sending for privacy. Do you consent to send this info?</string>
     <string name="identity_server_consent_dialog_neutral_policy">Policy</string>
 
     <string name="settings_discovery_enter_identity_server">Enter an identity server URL</string>
@@ -2431,6 +2438,7 @@
     <string name="attachment_type_audio">"Audio"</string>
     <string name="attachment_type_gallery">"Gallery"</string>
     <string name="attachment_type_sticker">"Sticker"</string>
+    <string name="attachment_type_poll">Poll</string>
     <string name="rotate_and_crop_screen_title">Rotate and crop</string>
     <string name="error_handling_incoming_share">Couldn\'t handle share data</string>
 
@@ -3626,4 +3634,18 @@
     <string name="link_this_email_settings_link">Link this email with your account</string>
     <!-- %s will be replaced by the value of link_this_email_settings_link and styled as a link -->
     <string name="link_this_email_with_your_account">%s in Settings to receive invites directly in SchildiChat.</string>
+
+    <!-- Poll -->
+    <string name="create_poll_title">Create Poll</string>
+    <string name="create_poll_question_title">Poll question or topic</string>
+    <string name="create_poll_question_hint">Question or topic</string>
+    <string name="create_poll_options_title">Create options</string>
+    <string name="create_poll_options_hint">Option %1$d</string>
+    <string name="create_poll_add_option">ADD OPTION</string>
+    <string name="create_poll_button">CREATE POLL</string>
+    <string name="create_poll_empty_question_error">Question cannot be empty</string>
+    <plurals name="create_poll_not_enough_options_error">
+        <item quantity="one">At least %1$s option is required</item>
+        <item quantity="other">At least %1$s options are required</item>
+    </plurals>
 </resources>
diff --git a/vector/src/test/java/im/vector/app/features/crypto/keys/KeysExporterTest.kt b/vector/src/test/java/im/vector/app/features/crypto/keys/KeysExporterTest.kt
index c75abf5db4..57ad2a52ab 100644
--- a/vector/src/test/java/im/vector/app/features/crypto/keys/KeysExporterTest.kt
+++ b/vector/src/test/java/im/vector/app/features/crypto/keys/KeysExporterTest.kt
@@ -42,7 +42,7 @@ class KeysExporterTest {
     private val keysExporter = KeysExporter(
             session = FakeSession(fakeCryptoService = cryptoService),
             context = context.instance,
-            dispatchers = CoroutineDispatchers(Dispatchers.Unconfined)
+            dispatchers = CoroutineDispatchers(Dispatchers.Unconfined, Dispatchers.Unconfined)
     )
 
     @Before
diff --git a/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt b/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt
index 0fff663972..ea9335aaff 100644
--- a/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt
+++ b/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt
@@ -18,10 +18,10 @@ package im.vector.app.features.crypto.quads
 
 import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.test.MvRxTestRule
-import im.vector.app.test.InstantRxRule
 import im.vector.app.test.fakes.FakeSession
 import im.vector.app.test.fakes.FakeStringProvider
 import im.vector.app.test.test
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Rule
 import org.junit.Test
 import org.matrix.android.sdk.api.session.securestorage.IntegrityResult
@@ -39,98 +39,120 @@ private val KEY_INFO_WITHOUT_PASSPHRASE = KeyInfo(id = "id", content = SecretSto
 
 class SharedSecureStorageViewModelTest {
 
-    @get:Rule
-    val instantRx = InstantRxRule()
     @get:Rule
     val mvrxTestRule = MvRxTestRule()
 
     private val stringProvider = FakeStringProvider()
     private val session = FakeSession()
+    val args = SharedSecureStorageActivity.Args(keyId = null, emptyList(), "alias")
 
     @Test
     fun `given a key info with passphrase when initialising then step is EnterPassphrase`() {
-        givenKey(KEY_INFO_WITH_PASSPHRASE)
-
-        val viewModel = createViewModel()
-
-        viewModel.test().assertState(aViewState(
-                hasPassphrase = true,
-                step = SharedSecureStorageViewState.Step.EnterPassphrase
-        ))
+        runBlockingTest {
+            givenKey(KEY_INFO_WITH_PASSPHRASE)
+            val viewModel = createViewModel()
+            viewModel
+                    .test(this)
+                    .assertState(aViewState(
+                            hasPassphrase = true,
+                            step = SharedSecureStorageViewState.Step.EnterPassphrase
+                    ))
+                    .finish()
+        }
     }
 
     @Test
     fun `given a key info without passphrase when initialising then step is EnterKey`() {
-        givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
+        runBlockingTest {
+            givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
 
-        val viewModel = createViewModel()
+            val viewModel = createViewModel()
 
-        viewModel.test().assertState(aViewState(
-                hasPassphrase = false,
-                step = SharedSecureStorageViewState.Step.EnterKey
-        ))
+            viewModel
+                    .test(this)
+                    .assertState(aViewState(
+                            hasPassphrase = false,
+                            step = SharedSecureStorageViewState.Step.EnterKey
+                    ))
+                    .finish()
+        }
     }
 
     @Test
     fun `given on EnterKey step when going back then dismisses`() {
-        givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
+        runBlockingTest {
+            givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
 
-        val viewModel = createViewModel()
-        val test = viewModel.test()
-
-        viewModel.handle(SharedSecureStorageAction.Back)
-
-        test.assertEvents(SharedSecureStorageViewEvent.Dismiss)
+            val viewModel = createViewModel()
+            val test = viewModel.test(this)
+            viewModel.handle(SharedSecureStorageAction.Back)
+            test
+                    .assertEvents(SharedSecureStorageViewEvent.Dismiss)
+                    .finish()
+        }
     }
 
     @Test
     fun `given on passphrase step when using key then step is EnterKey`() {
-        givenKey(KEY_INFO_WITH_PASSPHRASE)
-        val viewModel = createViewModel()
-        val test = viewModel.test()
+        runBlockingTest {
+            givenKey(KEY_INFO_WITH_PASSPHRASE)
+            val viewModel = createViewModel()
+            val test = viewModel.test(this)
 
-        viewModel.handle(SharedSecureStorageAction.UseKey)
+            viewModel.handle(SharedSecureStorageAction.UseKey)
 
-        test.assertState(aViewState(
-                hasPassphrase = true,
-                step = SharedSecureStorageViewState.Step.EnterKey
-        ))
+            test
+                    .assertState(aViewState(
+                            hasPassphrase = true,
+                            step = SharedSecureStorageViewState.Step.EnterKey
+                    ))
+                    .finish()
+        }
     }
 
     @Test
     fun `given a key info with passphrase and on EnterKey step when going back then step is EnterPassphrase`() {
-        givenKey(KEY_INFO_WITH_PASSPHRASE)
-        val viewModel = createViewModel()
-        val test = viewModel.test()
+        runBlockingTest {
+            givenKey(KEY_INFO_WITH_PASSPHRASE)
+            val viewModel = createViewModel()
+            val test = viewModel.test(this)
 
-        viewModel.handle(SharedSecureStorageAction.UseKey)
-        viewModel.handle(SharedSecureStorageAction.Back)
+            viewModel.handle(SharedSecureStorageAction.UseKey)
+            viewModel.handle(SharedSecureStorageAction.Back)
 
-        test.assertState(aViewState(
-                hasPassphrase = true,
-                step = SharedSecureStorageViewState.Step.EnterPassphrase
-        ))
+            test
+                    .assertState(aViewState(
+                    hasPassphrase = true,
+                    step = SharedSecureStorageViewState.Step.EnterPassphrase
+            ))
+                    .finish()
+        }
     }
 
     @Test
     fun `given on passphrase step when going back then dismisses`() {
-        givenKey(KEY_INFO_WITH_PASSPHRASE)
-        val viewModel = createViewModel()
-        val test = viewModel.test()
+        runBlockingTest {
+            givenKey(KEY_INFO_WITH_PASSPHRASE)
+            val viewModel = createViewModel()
+            val test = viewModel.test(this)
 
-        viewModel.handle(SharedSecureStorageAction.Back)
+            viewModel.handle(SharedSecureStorageAction.Back)
 
-        test.assertEvents(SharedSecureStorageViewEvent.Dismiss)
+            test
+                    .assertEvents(SharedSecureStorageViewEvent.Dismiss)
+                    .finish()
+        }
     }
 
-    private fun createViewModel() = SharedSecureStorageViewModel(
-            SharedSecureStorageViewState(),
-            SharedSecureStorageActivity.Args(keyId = null, emptyList(), "alias"),
-            stringProvider.instance,
-            session
-    )
+    private fun createViewModel(): SharedSecureStorageViewModel {
+        return SharedSecureStorageViewModel(
+                SharedSecureStorageViewState(args),
+                stringProvider.instance,
+                session
+        )
+    }
 
-    private fun aViewState(hasPassphrase: Boolean, step: SharedSecureStorageViewState.Step) = SharedSecureStorageViewState(
+    private fun aViewState(hasPassphrase: Boolean, step: SharedSecureStorageViewState.Step) = SharedSecureStorageViewState(args).copy(
             ready = true,
             hasPassphrase = hasPassphrase,
             checkingSSSSAction = Uninitialized,
diff --git a/vector/src/test/java/im/vector/app/features/notifications/NotifiableEventProcessorTest.kt b/vector/src/test/java/im/vector/app/features/notifications/NotifiableEventProcessorTest.kt
new file mode 100644
index 0000000000..131a423316
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/notifications/NotifiableEventProcessorTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import im.vector.app.features.notifications.ProcessedEvent.Type
+import im.vector.app.test.fakes.FakeAutoAcceptInvites
+import im.vector.app.test.fakes.FakeOutdatedEventDetector
+import im.vector.app.test.fixtures.aNotifiableMessageEvent
+import im.vector.app.test.fixtures.aSimpleNotifiableEvent
+import im.vector.app.test.fixtures.anInviteNotifiableEvent
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+import org.matrix.android.sdk.api.session.events.model.EventType
+
+private val NOT_VIEWING_A_ROOM: String? = null
+
+class NotifiableEventProcessorTest {
+
+    private val outdatedDetector = FakeOutdatedEventDetector()
+    private val autoAcceptInvites = FakeAutoAcceptInvites()
+
+    private val eventProcessor = NotifiableEventProcessor(outdatedDetector.instance, autoAcceptInvites)
+
+    @Test
+    fun `given simple events when processing then keep simple events`() {
+        val events = listOf(
+                aSimpleNotifiableEvent(eventId = "event-1"),
+                aSimpleNotifiableEvent(eventId = "event-2")
+        )
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.KEEP to events[0],
+                Type.KEEP to events[1]
+        )
+    }
+
+    @Test
+    fun `given redacted simple event when processing then remove redaction event`() {
+        val events = listOf(aSimpleNotifiableEvent(eventId = "event-1", type = EventType.REDACTION))
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.REMOVE to events[0]
+        )
+    }
+
+    @Test
+    fun `given invites are auto accepted when processing then remove invitations`() {
+        autoAcceptInvites._isEnabled = true
+        val events = listOf<NotifiableEvent>(
+                anInviteNotifiableEvent(roomId = "room-1"),
+                anInviteNotifiableEvent(roomId = "room-2")
+        )
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.REMOVE to events[0],
+                Type.REMOVE to events[1]
+        )
+    }
+
+    @Test
+    fun `given invites are not auto accepted when processing then keep invitation events`() {
+        autoAcceptInvites._isEnabled = false
+        val events = listOf(
+                anInviteNotifiableEvent(roomId = "room-1"),
+                anInviteNotifiableEvent(roomId = "room-2")
+        )
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.KEEP to events[0],
+                Type.KEEP to events[1]
+        )
+    }
+
+    @Test
+    fun `given out of date message event when processing then removes message event`() {
+        val events = listOf(aNotifiableMessageEvent(eventId = "event-1", roomId = "room-1"))
+        outdatedDetector.givenEventIsOutOfDate(events[0])
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.REMOVE to events[0],
+        )
+    }
+
+    @Test
+    fun `given in date message event when processing then keep message event`() {
+        val events = listOf(aNotifiableMessageEvent(eventId = "event-1", roomId = "room-1"))
+        outdatedDetector.givenEventIsInDate(events[0])
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.KEEP to events[0],
+        )
+    }
+
+    @Test
+    fun `given viewing the same room as message event when processing then removes message`() {
+        val events = listOf(aNotifiableMessageEvent(eventId = "event-1", roomId = "room-1"))
+
+        val result = eventProcessor.process(events, currentRoomId = "room-1", renderedEvents = emptyList())
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.REMOVE to events[0],
+        )
+    }
+
+    @Test
+    fun `given events are different to rendered events when processing then removes difference`() {
+        val events = listOf(aSimpleNotifiableEvent(eventId = "event-1"))
+        val renderedEvents = listOf<ProcessedEvent<NotifiableEvent>>(
+                ProcessedEvent(Type.KEEP, events[0]),
+                ProcessedEvent(Type.KEEP, anInviteNotifiableEvent(roomId = "event-2"))
+        )
+
+        val result = eventProcessor.process(events, currentRoomId = NOT_VIEWING_A_ROOM, renderedEvents = renderedEvents)
+
+        result shouldBeEqualTo listOfProcessedEvents(
+                Type.REMOVE to renderedEvents[1].event,
+                Type.KEEP to renderedEvents[0].event
+        )
+    }
+
+    private fun listOfProcessedEvents(vararg event: Pair<Type, NotifiableEvent>) = event.map {
+        ProcessedEvent(it.first, it.second)
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/features/notifications/NotificationEventQueueTest.kt b/vector/src/test/java/im/vector/app/features/notifications/NotificationEventQueueTest.kt
new file mode 100644
index 0000000000..26c0030d26
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/notifications/NotificationEventQueueTest.kt
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import im.vector.app.test.fixtures.aNotifiableMessageEvent
+import im.vector.app.test.fixtures.aSimpleNotifiableEvent
+import im.vector.app.test.fixtures.anInviteNotifiableEvent
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+
+class NotificationEventQueueTest {
+
+    private val seenIdsCache = CircularCache.create<String>(5)
+
+    @Test
+    fun `given events when redacting some then marks matching event ids as redacted`() {
+        val queue = givenQueue(listOf(
+                aSimpleNotifiableEvent(eventId = "redacted-id-1"),
+                aNotifiableMessageEvent(eventId = "redacted-id-2"),
+                anInviteNotifiableEvent(eventId = "redacted-id-3"),
+                aSimpleNotifiableEvent(eventId = "kept-id"),
+        ))
+
+        queue.markRedacted(listOf("redacted-id-1", "redacted-id-2", "redacted-id-3"))
+
+        queue.rawEvents() shouldBeEqualTo listOf(
+                aSimpleNotifiableEvent(eventId = "redacted-id-1", isRedacted = true),
+                aNotifiableMessageEvent(eventId = "redacted-id-2", isRedacted = true),
+                anInviteNotifiableEvent(eventId = "redacted-id-3", isRedacted = true),
+                aSimpleNotifiableEvent(eventId = "kept-id", isRedacted = false),
+        )
+    }
+
+    @Test
+    fun `given invite event when leaving invited room and syncing then removes event`() {
+        val queue = givenQueue(listOf(anInviteNotifiableEvent(roomId = "a-room-id")))
+        val roomsLeft = listOf("a-room-id")
+
+        queue.syncRoomEvents(roomsLeft = roomsLeft, roomsJoined = emptyList())
+
+        queue.rawEvents() shouldBeEqualTo emptyList()
+    }
+
+    @Test
+    fun `given invite event when joining invited room and syncing then removes event`() {
+        val queue = givenQueue(listOf(anInviteNotifiableEvent(roomId = "a-room-id")))
+        val joinedRooms = listOf("a-room-id")
+
+        queue.syncRoomEvents(roomsLeft = emptyList(), roomsJoined = joinedRooms)
+
+        queue.rawEvents() shouldBeEqualTo emptyList()
+    }
+
+    @Test
+    fun `given message event when leaving message room and syncing then removes event`() {
+        val queue = givenQueue(listOf(aNotifiableMessageEvent(roomId = "a-room-id")))
+        val roomsLeft = listOf("a-room-id")
+
+        queue.syncRoomEvents(roomsLeft = roomsLeft, roomsJoined = emptyList())
+
+        queue.rawEvents() shouldBeEqualTo emptyList()
+    }
+
+    @Test
+    fun `given events when syncing without rooms left or joined ids then does not change the events`() {
+        val queue = givenQueue(listOf(
+                aNotifiableMessageEvent(roomId = "a-room-id"),
+                anInviteNotifiableEvent(roomId = "a-room-id")
+        ))
+
+        queue.syncRoomEvents(roomsLeft = emptyList(), roomsJoined = emptyList())
+
+        queue.rawEvents() shouldBeEqualTo listOf(
+                aNotifiableMessageEvent(roomId = "a-room-id"),
+                anInviteNotifiableEvent(roomId = "a-room-id")
+        )
+    }
+
+    @Test
+    fun `given events then is not empty`() {
+        val queue = givenQueue(listOf(aSimpleNotifiableEvent()))
+
+        queue.isEmpty() shouldBeEqualTo false
+    }
+
+    @Test
+    fun `given no events then is empty`() {
+        val queue = givenQueue(emptyList())
+
+        queue.isEmpty() shouldBeEqualTo true
+    }
+
+    @Test
+    fun `given events when clearing and adding then removes previous events and adds only new events`() {
+        val queue = givenQueue(listOf(aSimpleNotifiableEvent()))
+
+        queue.clearAndAdd(listOf(anInviteNotifiableEvent()))
+
+        queue.rawEvents() shouldBeEqualTo listOf(anInviteNotifiableEvent())
+    }
+
+    @Test
+    fun `when clearing then is empty`() {
+        val queue = givenQueue(listOf(aSimpleNotifiableEvent()))
+
+        queue.clear()
+
+        queue.rawEvents() shouldBeEqualTo emptyList()
+    }
+
+    @Test
+    fun `given no events when adding then adds event`() {
+        val queue = givenQueue(listOf())
+
+        queue.add(aSimpleNotifiableEvent(), seenEventIds = seenIdsCache)
+
+        queue.rawEvents() shouldBeEqualTo listOf(aSimpleNotifiableEvent())
+    }
+
+    @Test
+    fun `given no events when adding already seen event then ignores event`() {
+        val queue = givenQueue(listOf())
+        val notifiableEvent = aSimpleNotifiableEvent()
+        seenIdsCache.put(notifiableEvent.eventId)
+
+        queue.add(notifiableEvent, seenEventIds = seenIdsCache)
+
+        queue.rawEvents() shouldBeEqualTo emptyList()
+    }
+
+    @Test
+    fun `given replaceable event when adding event with same id then updates existing event`() {
+        val replaceableEvent = aSimpleNotifiableEvent(canBeReplaced = true)
+        val updatedEvent = replaceableEvent.copy(title = "updated title")
+        val queue = givenQueue(listOf(replaceableEvent))
+
+        queue.add(updatedEvent, seenEventIds = seenIdsCache)
+
+        queue.rawEvents() shouldBeEqualTo listOf(updatedEvent)
+    }
+
+    @Test
+    fun `given non replaceable event when adding event with same id then ignores event`() {
+        val nonReplaceableEvent = aSimpleNotifiableEvent(canBeReplaced = false)
+        val updatedEvent = nonReplaceableEvent.copy(title = "updated title")
+        val queue = givenQueue(listOf(nonReplaceableEvent))
+
+        queue.add(updatedEvent, seenEventIds = seenIdsCache)
+
+        queue.rawEvents() shouldBeEqualTo listOf(nonReplaceableEvent)
+    }
+
+    @Test
+    fun `given event when adding new event with edited event id matching the existing event id then updates existing event`() {
+        val editedEvent = aSimpleNotifiableEvent(eventId = "id-to-edit")
+        val updatedEvent = editedEvent.copy(eventId = "1", editedEventId = "id-to-edit", title = "updated title")
+        val queue = givenQueue(listOf(editedEvent))
+
+        queue.add(updatedEvent, seenEventIds = seenIdsCache)
+
+        queue.rawEvents() shouldBeEqualTo listOf(updatedEvent)
+    }
+
+    @Test
+    fun `given event when adding new event with edited event id matching the existing event edited id then updates existing event`() {
+        val editedEvent = aSimpleNotifiableEvent(eventId = "0", editedEventId = "id-to-edit")
+        val updatedEvent = editedEvent.copy(eventId = "1", editedEventId = "id-to-edit", title = "updated title")
+        val queue = givenQueue(listOf(editedEvent))
+
+        queue.add(updatedEvent, seenEventIds = seenIdsCache)
+
+        queue.rawEvents() shouldBeEqualTo listOf(updatedEvent)
+    }
+
+    @Test
+    fun `when clearing membership notification then removes invite events with matching room id`() {
+        val roomId = "a-room-id"
+        val queue = givenQueue(listOf(
+                anInviteNotifiableEvent(roomId = roomId),
+                aNotifiableMessageEvent(roomId = roomId)
+        ))
+
+        queue.clearMemberShipNotificationForRoom(roomId)
+
+        queue.rawEvents() shouldBeEqualTo listOf(aNotifiableMessageEvent(roomId = roomId))
+    }
+
+    @Test
+    fun `when clearing messages for room then removes message events with matching room id`() {
+        val roomId = "a-room-id"
+        val queue = givenQueue(listOf(
+                anInviteNotifiableEvent(roomId = roomId),
+                aNotifiableMessageEvent(roomId = roomId)
+        ))
+
+        queue.clearMessagesForRoom(roomId)
+
+        queue.rawEvents() shouldBeEqualTo listOf(anInviteNotifiableEvent(roomId = roomId))
+    }
+
+    private fun givenQueue(events: List<NotifiableEvent>) = NotificationEventQueue(events.toMutableList())
+}
diff --git a/vector/src/test/java/im/vector/app/features/notifications/NotificationFactoryTest.kt b/vector/src/test/java/im/vector/app/features/notifications/NotificationFactoryTest.kt
new file mode 100644
index 0000000000..f0f9a4dbc7
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/notifications/NotificationFactoryTest.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import im.vector.app.features.notifications.ProcessedEvent.Type
+import im.vector.app.test.fakes.FakeNotificationUtils
+import im.vector.app.test.fakes.FakeRoomGroupMessageCreator
+import im.vector.app.test.fakes.FakeSummaryGroupMessageCreator
+import im.vector.app.test.fixtures.aNotifiableMessageEvent
+import im.vector.app.test.fixtures.aSimpleNotifiableEvent
+import im.vector.app.test.fixtures.anInviteNotifiableEvent
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+
+private const val MY_USER_ID = "user-id"
+private const val A_ROOM_ID = "room-id"
+private const val AN_EVENT_ID = "event-id"
+
+private val MY_AVATAR_URL: String? = null
+private val AN_INVITATION_EVENT = anInviteNotifiableEvent(roomId = A_ROOM_ID)
+private val A_SIMPLE_EVENT = aSimpleNotifiableEvent(eventId = AN_EVENT_ID)
+private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)
+
+class NotificationFactoryTest {
+
+    private val notificationUtils = FakeNotificationUtils()
+    private val roomGroupMessageCreator = FakeRoomGroupMessageCreator()
+    private val summaryGroupMessageCreator = FakeSummaryGroupMessageCreator()
+
+    private val notificationFactory = NotificationFactory(
+            notificationUtils.instance,
+            roomGroupMessageCreator.instance,
+            summaryGroupMessageCreator.instance
+    )
+
+    @Test
+    fun `given a room invitation when mapping to notification then is Append`() = testWith(notificationFactory) {
+        val expectedNotification = notificationUtils.givenBuildRoomInvitationNotificationFor(AN_INVITATION_EVENT, MY_USER_ID)
+        val roomInvitation = listOf(ProcessedEvent(Type.KEEP, AN_INVITATION_EVENT))
+
+        val result = roomInvitation.toNotifications(MY_USER_ID)
+
+        result shouldBeEqualTo listOf(OneShotNotification.Append(
+                notification = expectedNotification,
+                meta = OneShotNotification.Append.Meta(
+                        key = A_ROOM_ID,
+                        summaryLine = AN_INVITATION_EVENT.description,
+                        isNoisy = AN_INVITATION_EVENT.noisy,
+                        timestamp = AN_INVITATION_EVENT.timestamp
+                ))
+        )
+    }
+
+    @Test
+    fun `given a missing event in room invitation when mapping to notification then is Removed`() = testWith(notificationFactory) {
+        val missingEventRoomInvitation = listOf(ProcessedEvent(Type.REMOVE, AN_INVITATION_EVENT))
+
+        val result = missingEventRoomInvitation.toNotifications(MY_USER_ID)
+
+        result shouldBeEqualTo listOf(OneShotNotification.Removed(
+                key = A_ROOM_ID
+        ))
+    }
+
+    @Test
+    fun `given a simple event when mapping to notification then is Append`() = testWith(notificationFactory) {
+        val expectedNotification = notificationUtils.givenBuildSimpleInvitationNotificationFor(A_SIMPLE_EVENT, MY_USER_ID)
+        val roomInvitation = listOf(ProcessedEvent(Type.KEEP, A_SIMPLE_EVENT))
+
+        val result = roomInvitation.toNotifications(MY_USER_ID)
+
+        result shouldBeEqualTo listOf(OneShotNotification.Append(
+                notification = expectedNotification,
+                meta = OneShotNotification.Append.Meta(
+                        key = AN_EVENT_ID,
+                        summaryLine = A_SIMPLE_EVENT.description,
+                        isNoisy = A_SIMPLE_EVENT.noisy,
+                        timestamp = AN_INVITATION_EVENT.timestamp
+                ))
+        )
+    }
+
+    @Test
+    fun `given a missing simple event when mapping to notification then is Removed`() = testWith(notificationFactory) {
+        val missingEventRoomInvitation = listOf(ProcessedEvent(Type.REMOVE, A_SIMPLE_EVENT))
+
+        val result = missingEventRoomInvitation.toNotifications(MY_USER_ID)
+
+        result shouldBeEqualTo listOf(OneShotNotification.Removed(
+                key = AN_EVENT_ID
+        ))
+    }
+
+    @Test
+    fun `given room with message when mapping to notification then delegates to room group message creator`() = testWith(notificationFactory) {
+        val events = listOf(A_MESSAGE_EVENT)
+        val expectedNotification = roomGroupMessageCreator.givenCreatesRoomMessageFor(events, A_ROOM_ID, MY_USER_ID, MY_AVATAR_URL)
+        val roomWithMessage = mapOf(A_ROOM_ID to listOf(ProcessedEvent(Type.KEEP, A_MESSAGE_EVENT)))
+
+        val result = roomWithMessage.toNotifications(MY_USER_ID, MY_AVATAR_URL)
+
+        result shouldBeEqualTo listOf(expectedNotification)
+    }
+
+    @Test
+    fun `given a room with no events to display when mapping to notification then is Empty`() = testWith(notificationFactory) {
+        val events = listOf(ProcessedEvent(Type.REMOVE, A_MESSAGE_EVENT))
+        val emptyRoom = mapOf(A_ROOM_ID to events)
+
+        val result = emptyRoom.toNotifications(MY_USER_ID, MY_AVATAR_URL)
+
+        result shouldBeEqualTo listOf(RoomNotification.Removed(
+                roomId = A_ROOM_ID
+        ))
+    }
+
+    @Test
+    fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationFactory) {
+        val redactedRoom = mapOf(A_ROOM_ID to listOf(ProcessedEvent(Type.KEEP, A_MESSAGE_EVENT.copy(isRedacted = true))))
+
+        val result = redactedRoom.toNotifications(MY_USER_ID, MY_AVATAR_URL)
+
+        result shouldBeEqualTo listOf(RoomNotification.Removed(
+                roomId = A_ROOM_ID
+        ))
+    }
+
+    @Test
+    fun `given a room with redacted and non redacted message events when mapping to notification then redacted events are removed`() = testWith(notificationFactory) {
+        val roomWithRedactedMessage = mapOf(A_ROOM_ID to listOf(
+                ProcessedEvent(Type.KEEP, A_MESSAGE_EVENT.copy(isRedacted = true)),
+                ProcessedEvent(Type.KEEP, A_MESSAGE_EVENT.copy(eventId = "not-redacted"))
+        ))
+        val withRedactedRemoved = listOf(A_MESSAGE_EVENT.copy(eventId = "not-redacted"))
+        val expectedNotification = roomGroupMessageCreator.givenCreatesRoomMessageFor(withRedactedRemoved, A_ROOM_ID, MY_USER_ID, MY_AVATAR_URL)
+
+        val result = roomWithRedactedMessage.toNotifications(MY_USER_ID, MY_AVATAR_URL)
+
+        result shouldBeEqualTo listOf(expectedNotification)
+    }
+}
+
+fun <T> testWith(receiver: T, block: T.() -> Unit) {
+    receiver.block()
+}
diff --git a/vector/src/test/java/im/vector/app/features/notifications/NotificationRendererTest.kt b/vector/src/test/java/im/vector/app/features/notifications/NotificationRendererTest.kt
new file mode 100644
index 0000000000..6dca0479e7
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/notifications/NotificationRendererTest.kt
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.notifications
+
+import android.app.Notification
+import im.vector.app.test.fakes.FakeContext
+import im.vector.app.test.fakes.FakeNotificationDisplayer
+import im.vector.app.test.fakes.FakeNotificationFactory
+import io.mockk.mockk
+import org.junit.Test
+
+private const val MY_USER_ID = "my-user-id"
+private const val MY_USER_DISPLAY_NAME = "display-name"
+private const val MY_USER_AVATAR_URL = "avatar-url"
+private const val AN_EVENT_ID = "event-id"
+private const val A_ROOM_ID = "room-id"
+private const val USE_COMPLETE_NOTIFICATION_FORMAT = true
+
+private val AN_EVENT_LIST = listOf<ProcessedEvent<NotifiableEvent>>()
+private val A_PROCESSED_EVENTS = GroupedNotificationEvents(emptyMap(), emptyList(), emptyList())
+private val A_SUMMARY_NOTIFICATION = SummaryNotification.Update(mockk())
+private val A_REMOVE_SUMMARY_NOTIFICATION = SummaryNotification.Removed
+private val A_NOTIFICATION = mockk<Notification>()
+private val MESSAGE_META = RoomNotification.Message.Meta(
+        summaryLine = "ignored", messageCount = 1, latestTimestamp = -1, roomId = A_ROOM_ID, shouldBing = false
+)
+private val ONE_SHOT_META = OneShotNotification.Append.Meta(key = "ignored", summaryLine = "ignored", isNoisy = false, timestamp = -1)
+
+class NotificationRendererTest {
+
+    private val context = FakeContext()
+    private val notificationDisplayer = FakeNotificationDisplayer()
+    private val notificationFactory = FakeNotificationFactory()
+
+    private val notificationRenderer = NotificationRenderer(
+            notificationDisplayer = notificationDisplayer.instance,
+            notificationFactory = notificationFactory.instance,
+            appContext = context.instance
+    )
+
+    @Test
+    fun `given no notifications when rendering then cancels summary notification`() {
+        givenNoNotifications()
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifySummaryCancelled()
+        notificationDisplayer.verifyNoOtherInteractions()
+    }
+
+    @Test
+    fun `given last room message group notification is removed when rendering then remove the summary and then remove message notification`() {
+        givenNotifications(roomNotifications = listOf(RoomNotification.Removed(A_ROOM_ID)), summaryNotification = A_REMOVE_SUMMARY_NOTIFICATION)
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            cancelNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID)
+            cancelNotificationMessage(tag = A_ROOM_ID, NotificationDrawerManager.ROOM_MESSAGES_NOTIFICATION_ID)
+        }
+    }
+
+    @Test
+    fun `given a room message group notification is removed when rendering then remove the message notification and update summary`() {
+        givenNotifications(roomNotifications = listOf(RoomNotification.Removed(A_ROOM_ID)))
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            cancelNotificationMessage(tag = A_ROOM_ID, NotificationDrawerManager.ROOM_MESSAGES_NOTIFICATION_ID)
+            showNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID, A_SUMMARY_NOTIFICATION.notification)
+        }
+    }
+
+    @Test
+    fun `given a room message group notification is added when rendering then show the message notification and update summary`() {
+        givenNotifications(roomNotifications = listOf(RoomNotification.Message(
+                A_NOTIFICATION,
+                MESSAGE_META
+        )))
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            showNotificationMessage(tag = A_ROOM_ID, NotificationDrawerManager.ROOM_MESSAGES_NOTIFICATION_ID, A_NOTIFICATION)
+            showNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID, A_SUMMARY_NOTIFICATION.notification)
+        }
+    }
+
+    @Test
+    fun `given last simple notification is removed when rendering then remove the summary and then remove simple notification`() {
+        givenNotifications(simpleNotifications = listOf(OneShotNotification.Removed(AN_EVENT_ID)), summaryNotification = A_REMOVE_SUMMARY_NOTIFICATION)
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            cancelNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID)
+            cancelNotificationMessage(tag = AN_EVENT_ID, NotificationDrawerManager.ROOM_EVENT_NOTIFICATION_ID)
+        }
+    }
+
+    @Test
+    fun `given a simple notification is removed when rendering then remove the simple notification and update summary`() {
+        givenNotifications(simpleNotifications = listOf(OneShotNotification.Removed(AN_EVENT_ID)))
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            cancelNotificationMessage(tag = AN_EVENT_ID, NotificationDrawerManager.ROOM_EVENT_NOTIFICATION_ID)
+            showNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID, A_SUMMARY_NOTIFICATION.notification)
+        }
+    }
+
+    @Test
+    fun `given a simple notification is added when rendering then show the simple notification and update summary`() {
+        givenNotifications(simpleNotifications = listOf(OneShotNotification.Append(
+                A_NOTIFICATION,
+                ONE_SHOT_META.copy(key = AN_EVENT_ID)
+        )))
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            showNotificationMessage(tag = AN_EVENT_ID, NotificationDrawerManager.ROOM_EVENT_NOTIFICATION_ID, A_NOTIFICATION)
+            showNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID, A_SUMMARY_NOTIFICATION.notification)
+        }
+    }
+
+    @Test
+    fun `given last invitation notification is removed when rendering then remove the summary and then remove invitation notification`() {
+        givenNotifications(invitationNotifications = listOf(OneShotNotification.Removed(A_ROOM_ID)), summaryNotification = A_REMOVE_SUMMARY_NOTIFICATION)
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            cancelNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID)
+            cancelNotificationMessage(tag = A_ROOM_ID, NotificationDrawerManager.ROOM_INVITATION_NOTIFICATION_ID)
+        }
+    }
+
+    @Test
+    fun `given an invitation notification is removed when rendering then remove the invitation notification and update summary`() {
+        givenNotifications(invitationNotifications = listOf(OneShotNotification.Removed(A_ROOM_ID)))
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            cancelNotificationMessage(tag = A_ROOM_ID, NotificationDrawerManager.ROOM_INVITATION_NOTIFICATION_ID)
+            showNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID, A_SUMMARY_NOTIFICATION.notification)
+        }
+    }
+
+    @Test
+    fun `given an invitation notification is added when rendering then show the invitation notification and update summary`() {
+        givenNotifications(simpleNotifications = listOf(OneShotNotification.Append(
+                A_NOTIFICATION,
+                ONE_SHOT_META.copy(key = A_ROOM_ID)
+        )))
+
+        renderEventsAsNotifications()
+
+        notificationDisplayer.verifyInOrder {
+            showNotificationMessage(tag = A_ROOM_ID, NotificationDrawerManager.ROOM_EVENT_NOTIFICATION_ID, A_NOTIFICATION)
+            showNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID, A_SUMMARY_NOTIFICATION.notification)
+        }
+    }
+
+    private fun renderEventsAsNotifications() {
+        notificationRenderer.render(
+                myUserId = MY_USER_ID,
+                myUserDisplayName = MY_USER_DISPLAY_NAME,
+                myUserAvatarUrl = MY_USER_AVATAR_URL,
+                useCompleteNotificationFormat = USE_COMPLETE_NOTIFICATION_FORMAT,
+                eventsToProcess = AN_EVENT_LIST
+        )
+    }
+
+    private fun givenNoNotifications() {
+        givenNotifications(emptyList(), emptyList(), emptyList(), USE_COMPLETE_NOTIFICATION_FORMAT, A_REMOVE_SUMMARY_NOTIFICATION)
+    }
+
+    private fun givenNotifications(roomNotifications: List<RoomNotification> = emptyList(),
+                                   invitationNotifications: List<OneShotNotification> = emptyList(),
+                                   simpleNotifications: List<OneShotNotification> = emptyList(),
+                                   useCompleteNotificationFormat: Boolean = USE_COMPLETE_NOTIFICATION_FORMAT,
+                                   summaryNotification: SummaryNotification = A_SUMMARY_NOTIFICATION) {
+        notificationFactory.givenNotificationsFor(
+                groupedEvents = A_PROCESSED_EVENTS,
+                myUserId = MY_USER_ID,
+                myUserDisplayName = MY_USER_DISPLAY_NAME,
+                myUserAvatarUrl = MY_USER_AVATAR_URL,
+                useCompleteNotificationFormat = useCompleteNotificationFormat,
+                roomNotifications = roomNotifications,
+                invitationNotifications = invitationNotifications,
+                simpleNotifications = simpleNotifications,
+                summaryNotification = summaryNotification
+        )
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/Extensions.kt b/vector/src/test/java/im/vector/app/test/Extensions.kt
index f2a087fd52..e883df9906 100644
--- a/vector/src/test/java/im/vector/app/test/Extensions.kt
+++ b/vector/src/test/java/im/vector/app/test/Extensions.kt
@@ -20,27 +20,33 @@ import com.airbnb.mvrx.MavericksState
 import im.vector.app.core.platform.VectorViewEvents
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.platform.VectorViewModelAction
-import io.reactivex.observers.TestObserver
+import kotlinx.coroutines.CoroutineScope
 import org.amshove.kluent.shouldBeEqualTo
 
 fun String.trimIndentOneLine() = trimIndent().replace("\n", "")
 
-fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(): ViewModelTest<S, VE> {
+fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(coroutineScope: CoroutineScope): ViewModelTest<S, VE> {
     val state = { com.airbnb.mvrx.withState(this) { it } }
-    val viewEvents = viewEvents.observe().test()
+    val viewEvents = viewEvents.stream().test(coroutineScope)
     return ViewModelTest(state, viewEvents)
 }
 
 class ViewModelTest<S, VE>(
         val state: () -> S,
-        val viewEvents: TestObserver<VE>
+        val viewEvents: FlowTestObserver<VE>
 ) {
 
-    fun assertEvents(vararg expected: VE) {
+    fun assertEvents(vararg expected: VE): ViewModelTest<S, VE> {
         viewEvents.assertValues(*expected)
+        return this
     }
 
-    fun assertState(expected: S) {
+    fun assertState(expected: S): ViewModelTest<S, VE> {
         state() shouldBeEqualTo expected
+        return this
+    }
+
+    fun finish() {
+        viewEvents.finish()
     }
 }
diff --git a/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt b/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt
new file mode 100644
index 0000000000..955922d0c4
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import org.junit.Assert.assertEquals
+
+fun <T> Flow<T>.test(scope: CoroutineScope): FlowTestObserver<T> {
+    return FlowTestObserver(scope, this)
+}
+
+class FlowTestObserver<T>(
+        scope: CoroutineScope,
+        flow: Flow<T>
+) {
+    private val values = mutableListOf<T>()
+    private val job: Job = flow
+            .onEach {
+                values.add(it)
+            }.launchIn(scope)
+
+    fun assertNoValues(): FlowTestObserver<T> {
+        assertEquals(emptyList<T>(), this.values)
+        return this
+    }
+
+    fun assertValues(vararg values: T): FlowTestObserver<T> {
+        assertEquals(values.toList(), this.values)
+        return this
+    }
+
+    fun finish() {
+        job.cancel()
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt
new file mode 100644
index 0000000000..778c2f113d
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeAutoAcceptInvites.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.invite.AutoAcceptInvites
+
+class FakeAutoAcceptInvites : AutoAcceptInvites {
+
+    var _isEnabled: Boolean = false
+
+    override val isEnabled: Boolean
+        get() = _isEnabled
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationDisplayer.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationDisplayer.kt
new file mode 100644
index 0000000000..2856b0f49c
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationDisplayer.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.notifications.NotificationDisplayer
+import im.vector.app.features.notifications.NotificationDrawerManager
+import io.mockk.confirmVerified
+import io.mockk.mockk
+import io.mockk.verify
+import io.mockk.verifyOrder
+
+class FakeNotificationDisplayer {
+
+    val instance = mockk<NotificationDisplayer>(relaxed = true)
+
+    fun verifySummaryCancelled() {
+        verify { instance.cancelNotificationMessage(tag = null, NotificationDrawerManager.SUMMARY_NOTIFICATION_ID) }
+    }
+
+    fun verifyNoOtherInteractions() {
+        confirmVerified(instance)
+    }
+
+    fun verifyInOrder(verifyBlock: NotificationDisplayer.() -> Unit) {
+        verifyOrder { verifyBlock(instance) }
+        verifyNoOtherInteractions()
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationFactory.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationFactory.kt
new file mode 100644
index 0000000000..a6e7d1a078
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationFactory.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.notifications.GroupedNotificationEvents
+import im.vector.app.features.notifications.NotificationFactory
+import im.vector.app.features.notifications.OneShotNotification
+import im.vector.app.features.notifications.RoomNotification
+import im.vector.app.features.notifications.SummaryNotification
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeNotificationFactory {
+
+    val instance = mockk<NotificationFactory>()
+
+    fun givenNotificationsFor(groupedEvents: GroupedNotificationEvents,
+                              myUserId: String,
+                              myUserDisplayName: String,
+                              myUserAvatarUrl: String?,
+                              useCompleteNotificationFormat: Boolean,
+                              roomNotifications: List<RoomNotification>,
+                              invitationNotifications: List<OneShotNotification>,
+                              simpleNotifications: List<OneShotNotification>,
+                              summaryNotification: SummaryNotification) {
+        with(instance) {
+            every { groupedEvents.roomEvents.toNotifications(myUserDisplayName, myUserAvatarUrl) } returns roomNotifications
+            every { groupedEvents.invitationEvents.toNotifications(myUserId) } returns invitationNotifications
+            every { groupedEvents.simpleEvents.toNotifications(myUserId) } returns simpleNotifications
+
+            every {
+                createSummaryNotification(
+                        roomNotifications,
+                        invitationNotifications,
+                        simpleNotifications,
+                        useCompleteNotificationFormat
+                )
+            } returns summaryNotification
+        }
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationUtils.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationUtils.kt
new file mode 100644
index 0000000000..39f2ad59ff
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeNotificationUtils.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import android.app.Notification
+import im.vector.app.features.notifications.InviteNotifiableEvent
+import im.vector.app.features.notifications.NotificationUtils
+import im.vector.app.features.notifications.SimpleNotifiableEvent
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeNotificationUtils {
+
+    val instance = mockk<NotificationUtils>()
+
+    fun givenBuildRoomInvitationNotificationFor(event: InviteNotifiableEvent, myUserId: String): Notification {
+        val mockNotification = mockk<Notification>()
+        every { instance.buildRoomInvitationNotification(event, myUserId) } returns mockNotification
+        return mockNotification
+    }
+
+    fun givenBuildSimpleInvitationNotificationFor(event: SimpleNotifiableEvent, myUserId: String): Notification {
+        val mockNotification = mockk<Notification>()
+        every { instance.buildSimpleEventNotification(event, myUserId) } returns mockNotification
+        return mockNotification
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeOutdatedEventDetector.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeOutdatedEventDetector.kt
new file mode 100644
index 0000000000..0e1d617ca2
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeOutdatedEventDetector.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.notifications.NotifiableEvent
+import im.vector.app.features.notifications.OutdatedEventDetector
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeOutdatedEventDetector {
+    val instance = mockk<OutdatedEventDetector>()
+
+    fun givenEventIsOutOfDate(notifiableEvent: NotifiableEvent) {
+        every { instance.isMessageOutdated(notifiableEvent) } returns true
+    }
+
+    fun givenEventIsInDate(notifiableEvent: NotifiableEvent) {
+        every { instance.isMessageOutdated(notifiableEvent) } returns false
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeRoomGroupMessageCreator.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeRoomGroupMessageCreator.kt
new file mode 100644
index 0000000000..c164b9a661
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeRoomGroupMessageCreator.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.notifications.NotifiableMessageEvent
+import im.vector.app.features.notifications.RoomGroupMessageCreator
+import im.vector.app.features.notifications.RoomNotification
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeRoomGroupMessageCreator {
+
+    val instance = mockk<RoomGroupMessageCreator>()
+
+    fun givenCreatesRoomMessageFor(events: List<NotifiableMessageEvent>,
+                                   roomId: String,
+                                   userDisplayName: String,
+                                   userAvatarUrl: String?): RoomNotification.Message {
+        val mockMessage = mockk<RoomNotification.Message>()
+        every { instance.createRoomMessage(events, roomId, userDisplayName, userAvatarUrl) } returns mockMessage
+        return mockMessage
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSummaryGroupMessageCreator.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSummaryGroupMessageCreator.kt
new file mode 100644
index 0000000000..eef77298a0
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSummaryGroupMessageCreator.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.notifications.SummaryGroupMessageCreator
+import io.mockk.mockk
+
+class FakeSummaryGroupMessageCreator {
+
+    val instance = mockk<SummaryGroupMessageCreator>()
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt
new file mode 100644
index 0000000000..eb8f9ac413
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import im.vector.app.features.settings.VectorPreferences
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeVectorPreferences {
+
+    val instance = mockk<VectorPreferences>()
+
+    fun givenUseCompleteNotificationFormat(value: Boolean) {
+        every { instance.useCompleteNotificationFormat() } returns value
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fixtures/NotifiableEventFixture.kt b/vector/src/test/java/im/vector/app/test/fixtures/NotifiableEventFixture.kt
new file mode 100644
index 0000000000..53d38aa228
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fixtures/NotifiableEventFixture.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fixtures
+
+import im.vector.app.features.notifications.InviteNotifiableEvent
+import im.vector.app.features.notifications.NotifiableMessageEvent
+import im.vector.app.features.notifications.SimpleNotifiableEvent
+
+fun aSimpleNotifiableEvent(
+        eventId: String = "simple-event-id",
+        type: String? = null,
+        isRedacted: Boolean = false,
+        canBeReplaced: Boolean = false,
+        editedEventId: String? = null
+) = SimpleNotifiableEvent(
+        matrixID = null,
+        eventId = eventId,
+        editedEventId = editedEventId,
+        noisy = false,
+        title = "title",
+        description = "description",
+        type = type,
+        timestamp = 0,
+        soundName = null,
+        canBeReplaced = canBeReplaced,
+        isRedacted = isRedacted
+)
+
+fun anInviteNotifiableEvent(
+        roomId: String = "an-invite-room-id",
+        eventId: String = "invite-event-id",
+        isRedacted: Boolean = false
+) = InviteNotifiableEvent(
+        matrixID = null,
+        eventId = eventId,
+        roomId = roomId,
+        roomName = "a room name",
+        editedEventId = null,
+        noisy = false,
+        title = "title",
+        description = "description",
+        type = null,
+        timestamp = 0,
+        soundName = null,
+        canBeReplaced = false,
+        isRedacted = isRedacted
+)
+
+fun aNotifiableMessageEvent(
+        eventId: String = "a-message-event-id",
+        roomId: String = "a-message-room-id",
+        isRedacted: Boolean = false
+) = NotifiableMessageEvent(
+        eventId = eventId,
+        editedEventId = null,
+        noisy = false,
+        timestamp = 0,
+        senderName = "sender-name",
+        senderId = "sending-id",
+        body = "message-body",
+        roomId = roomId,
+        roomName = "room-name",
+        roomIsDirect = false,
+        canBeReplaced = false,
+        isRedacted = isRedacted,
+        imageUri = null
+)