diff --git a/app/build.gradle b/app/build.gradle
index c130bae25d629221f5e4b64a9f0bd608d520f366..cfd661ff35416bdeba2124d8d53e4bdb0166d4f9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -105,7 +105,7 @@ dependencies {
     implementation project(path: ':gallery')
 
     //Firebase
-    gplayImplementation platform('com.google.firebase:firebase-bom:32.7.2')
+    gplayImplementation platform('com.google.firebase:firebase-bom:32.7.4')
     gplayImplementation 'com.google.firebase:firebase-crashlytics-ktx'
     gplayImplementation 'com.google.firebase:firebase-analytics-ktx'
     gplayImplementation 'com.google.firebase:firebase-messaging-ktx'
diff --git a/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt b/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt
index 77b7a50edf43ef92c14a69a0d69a53ffd667f987..d639cd939f4109e6007ef70d3acc8664b48ffb4b 100644
--- a/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt
+++ b/app/src/main/java/org/futo/circles/feature/home/HomeFragment.kt
@@ -140,7 +140,7 @@ class HomeFragment : Fragment(R.layout.fragment_bottom_navigation), DeepLinkInte
         }
         viewModel.syncStateLiveData.observeData(this) {
             if (it is SyncState.Running && it.afterPause) {
-                syncLoadingDialog.handleLoading(LoadingData(org.futo.circles.auth.R.string.initial_sync))
+                syncLoadingDialog.handleLoading(LoadingData(org.futo.circles.auth.R.string.session_sync))
             } else syncLoadingDialog.dismiss()
         }
     }
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt b/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt
index 9b749b3df705cc6f1d39460d6bb65b9d0dc9f2b9..23ecfaa3c0d36aa57121e8d6468ea5b731049325 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt
@@ -5,6 +5,7 @@ import android.net.Uri
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
 import org.futo.circles.core.extensions.notEmptyDisplayName
+import org.futo.circles.core.utils.circlesRoomsTypes
 import org.futo.circles.model.InviteNotifiableEvent
 import org.futo.circles.model.NotifiableEvent
 import org.futo.circles.model.NotifiableMessageEvent
@@ -49,6 +50,11 @@ class NotifiableEventResolver @Inject constructor(
     suspend fun resolveEvent(event: Event, session: Session): NotifiableEvent? {
         val roomID = event.roomId ?: return null
         val eventId = event.eventId ?: return null
+
+        // filter
+        val roomType = session.getRoom(roomID)?.roomSummary()?.roomType
+        if (roomType !in circlesRoomsTypes) return null
+
         if (event.getClearType() == EventType.STATE_ROOM_MEMBER) {
             return resolveStateRoomEvent(event, session)
         }
diff --git a/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt b/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt
index bd0b1f1831d8b78a169b26fadb159d6a9798ba24..7a2a90a277ec57fb32999218c9d67a2453831ae2 100644
--- a/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt
+++ b/app/src/main/java/org/futo/circles/feature/people/PeopleDataSource.kt
@@ -6,7 +6,6 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.withContext
 import org.futo.circles.core.feature.room.knoks.KnockRequestsDataSource
 import org.futo.circles.core.feature.select_users.SearchUserDataSource
@@ -28,9 +27,7 @@ class PeopleDataSource @Inject constructor(
 
     private fun getKnockRequestCountFlow(): Flow<Int> =
         knockRequestsDataSource.getKnockRequestsListItemsLiveData(peopleCategoryDataSource.getProfileRoomId())
-            ?.map {
-                it.size
-            }?.asFlow() ?: flowOf()
+            .map { it.size }.asFlow()
 
     private fun getProfileSpaceInvitesCountFlow() =
         getSpacesLiveData(listOf(Membership.INVITE)).map { it.size }.asFlow()
diff --git a/app/src/main/java/org/futo/circles/view/SimpleTextWatcher.kt b/app/src/main/java/org/futo/circles/view/SimpleTextWatcher.kt
deleted file mode 100644
index d471738bd4a6fecc6bf8f737e20858a25a5a0e78..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/view/SimpleTextWatcher.kt
+++ /dev/null
@@ -1,37 +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 org.futo.circles.view
-
-import android.text.Editable
-import android.text.TextWatcher
-
-/**
- * TextWatcher with default no op implementation.
- */
-open class SimpleTextWatcher : TextWatcher {
-    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-        // No op
-    }
-
-    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-        // No op
-    }
-
-    override fun afterTextChanged(s: Editable) {
-        // No op
-    }
-}
diff --git a/app/src/main/java/org/futo/circles/view/UriContentListener.kt b/app/src/main/java/org/futo/circles/view/UriContentListener.kt
deleted file mode 100644
index 3cc04857fddff947b9ee079e09e7455eb073e60d..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/view/UriContentListener.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2023 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 org.futo.circles.view
-
-import android.content.ClipData
-import android.net.Uri
-import android.view.View
-import androidx.core.view.ContentInfoCompat
-import androidx.core.view.OnReceiveContentListener
-
-class UriContentListener(
-        private val onContent: (uri: Uri) -> Unit
-) : OnReceiveContentListener {
-    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
-        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 ...
-                onContent(uri)
-            }
-        }
-        // 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 remaining
-    }
-}
diff --git a/app/src/main/res/drawable/bg_code_block.xml b/app/src/main/res/drawable/bg_code_block.xml
deleted file mode 100644
index ef7227f6842b28bc38823dbcb26415fed7bde875..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/bg_code_block.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#F4F6FA" />
-    <stroke
-        android:width="@dimen/code_block_border_width"
-        android:color="#E3E8F0" />
-    <corners android:radius="@dimen/code_block_border_radius" />
-</shape>
diff --git a/app/src/main/res/drawable/ic_check_box.xml b/app/src/main/res/drawable/ic_check_box.xml
deleted file mode 100644
index 92c21a81c2284293ee353b1e992424321db858d8..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_check_box.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:tint="@color/menu_icon_color"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path
-        android:fillColor="#000000"
-        android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,5h14v14zM17.99,9l-1.41,-1.42 -6.59,6.59 -2.58,-2.57 -1.42,1.41 4,3.99z" />
-</vector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_composer_bold.xml b/app/src/main/res/drawable/ic_composer_bold.xml
deleted file mode 100644
index d2e26cf1e59a3105483837beaadd6acbfeadf1cb..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_bold.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:fillColor="@color/blue"
-        android:fillType="evenOdd"
-        android:pathData="M16,14.5C16,13.672 16.672,13 17.5,13H22.288C25.139,13 27.25,15.466 27.25,18.25C27.25,19.38 26.902,20.458 26.298,21.34C27.765,22.268 28.75,23.882 28.75,25.75C28.75,28.689 26.311,31 23.393,31H17.5C16.672,31 16,30.328 16,29.5V14.5ZM19,16V20.5H22.288C23.261,20.5 24.25,19.608 24.25,18.25C24.25,16.892 23.261,16 22.288,16H19ZM19,23.5V28H23.393C24.735,28 25.75,26.953 25.75,25.75C25.75,24.547 24.735,23.5 23.393,23.5H19Z" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_bullet_list.xml b/app/src/main/res/drawable/ic_composer_bullet_list.xml
deleted file mode 100644
index d372209ced344182d558b43d73f89df20eaa9307..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_bullet_list.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <group>
-        <clip-path android:pathData="M10,10h24v24h-24z" />
-        <path
-            android:fillColor="@color/blue"
-            android:pathData="M14,20.5C13.17,20.5 12.5,21.17 12.5,22C12.5,22.83 13.17,23.5 14,23.5C14.83,23.5 15.5,22.83 15.5,22C15.5,21.17 14.83,20.5 14,20.5ZM14,14.5C13.17,14.5 12.5,15.17 12.5,16C12.5,16.83 13.17,17.5 14,17.5C14.83,17.5 15.5,16.83 15.5,16C15.5,15.17 14.83,14.5 14,14.5ZM14,26.5C13.17,26.5 12.5,27.18 12.5,28C12.5,28.82 13.18,29.5 14,29.5C14.82,29.5 15.5,28.82 15.5,28C15.5,27.18 14.83,26.5 14,26.5ZM18,29H30C30.55,29 31,28.55 31,28C31,27.45 30.55,27 30,27H18C17.45,27 17,27.45 17,28C17,28.55 17.45,29 18,29ZM18,23H30C30.55,23 31,22.55 31,22C31,21.45 30.55,21 30,21H18C17.45,21 17,21.45 17,22C17,22.55 17.45,23 18,23ZM17,16C17,16.55 17.45,17 18,17H30C30.55,17 31,16.55 31,16C31,15.45 30.55,15 30,15H18C17.45,15 17,15.45 17,16Z" />
-    </group>
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_code_block.xml b/app/src/main/res/drawable/ic_composer_code_block.xml
deleted file mode 100644
index aaa3dbe78da6559eef7d6eb4c6c35e1dd7c9b32b..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_code_block.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:tint="@color/menu_icon_color"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:fillColor="@color/white"
-        android:pathData="m18,22c0.7,-0.72 1.4,-1.4 2.1,-2.1 0.68,-0.98 -0.93,-1.9 -1.5,-0.96 -0.87,0.88 -1.8,1.7 -2.6,2.6 -0.45,0.67 0.27,1.2 0.7,1.6 0.75,0.74 1.5,1.5 2.2,2.2 0.98,0.68 1.9,-0.93 0.96,-1.5l-1.9,-1.9zM26.6,22c-0.71,0.72 -1.5,1.4 -2.1,2.2 -0.68,0.98 0.93,1.9 1.5,0.96 0.88,-0.89 1.8,-1.8 2.6,-2.7 0.45,-0.67 -0.27,-1.2 -0.7,-1.6 -0.75,-0.74 -1.5,-1.5 -2.2,-2.2 -0.99,-0.66 -2,0.94 -0.96,1.5l1.9,1.9zM13.6,32c-1.1,0.021 -1.9,-1 -1.7,-2.1 0.005,-5.7 -0.011,-11 0.008,-17 0.088,-1 1.1,-1.7 2.1,-1.5 5.6,0.005 11,-0.011 17,0.008 1,0.088 1.7,1.1 1.5,2.1 -0.005,5.6 0.011,11 -0.008,17 -0.088,1 -1.1,1.7 -2.1,1.5h-17zM13.6,30.3h17v-17h-17v17z" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_indent.xml b/app/src/main/res/drawable/ic_composer_indent.xml
deleted file mode 100644
index cbef736659cf55c7868cf0ddad15fd7a0acf24f8..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_indent.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:tint="@color/menu_icon_color"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <group>
-        <clip-path android:pathData="M10,10h24v24h-24z" />
-        <path
-            android:fillColor="@color/blue"
-            android:pathData="M14,31H30C30.55,31 31,30.55 31,30C31,29.45 30.55,29 30,29H14C13.45,29 13,29.45 13,30C13,30.55 13.45,31 14,31ZM13,19.21V24.8C13,25.25 13.54,25.47 13.85,25.15L16.64,22.36C16.84,22.16 16.84,21.85 16.64,21.65L13.85,18.85C13.54,18.54 13,18.76 13,19.21ZM22,27H30C30.55,27 31,26.55 31,26C31,25.45 30.55,25 30,25H22C21.45,25 21,25.45 21,26C21,26.55 21.45,27 22,27ZM13,14C13,14.55 13.45,15 14,15H30C30.55,15 31,14.55 31,14C31,13.45 30.55,13 30,13H14C13.45,13 13,13.45 13,14ZM22,19H30C30.55,19 31,18.55 31,18C31,17.45 30.55,17 30,17H22C21.45,17 21,17.45 21,18C21,18.55 21.45,19 22,19ZM22,23H30C30.55,23 31,22.55 31,22C31,21.45 30.55,21 30,21H22C21.45,21 21,21.45 21,22C21,22.55 21.45,23 22,23Z" />
-    </group>
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_inline_code.xml b/app/src/main/res/drawable/ic_composer_inline_code.xml
deleted file mode 100644
index bc054e639a79590165c84994b991961df2579493..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_inline_code.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:fillColor="@color/blue"
-        android:pathData="M24.958,15.621C25.117,15.092 24.816,14.534 24.287,14.375C23.758,14.217 23.201,14.517 23.042,15.046L19.042,28.379C18.883,28.908 19.184,29.466 19.713,29.624C20.242,29.783 20.799,29.483 20.958,28.954L24.958,15.621Z" />
-    <path
-        android:fillColor="@color/blue"
-        android:pathData="M15.974,17.232C15.549,16.878 14.919,16.936 14.565,17.36L11.232,21.36C10.923,21.731 10.923,22.269 11.232,22.64L14.565,26.64C14.919,27.065 15.549,27.122 15.974,26.768C16.398,26.415 16.455,25.784 16.102,25.36L13.302,22L16.102,18.64C16.455,18.216 16.398,17.585 15.974,17.232Z" />
-    <path
-        android:fillColor="@color/blue"
-        android:pathData="M28.027,17.232C28.451,16.878 29.081,16.936 29.435,17.36L32.768,21.36C33.077,21.731 33.077,22.269 32.768,22.64L29.435,26.64C29.081,27.065 28.451,27.122 28.027,26.768C27.602,26.415 27.545,25.784 27.898,25.36L30.698,22L27.898,18.64C27.545,18.216 27.602,17.585 28.027,17.232Z" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_italic.xml b/app/src/main/res/drawable/ic_composer_italic.xml
deleted file mode 100644
index 15c40a206504405f3a9bb5fbb2056e3da01512e2..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_italic.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:pathData="M22.619,14.999L19.747,29.005H17.2C16.758,29.005 16.4,29.363 16.4,29.805C16.4,30.247 16.758,30.605 17.2,30.605H20.389C20.397,30.605 20.405,30.605 20.412,30.605H23.6C24.042,30.605 24.4,30.247 24.4,29.805C24.4,29.363 24.042,29.005 23.6,29.005H21.381L24.253,14.999H26.8C27.242,14.999 27.6,14.64 27.6,14.199C27.6,13.757 27.242,13.399 26.8,13.399H23.615C23.604,13.398 23.594,13.398 23.583,13.399H20.4C19.958,13.399 19.6,13.757 19.6,14.199C19.6,14.64 19.958,14.999 20.4,14.999H22.619Z"
-        android:fillColor="@color/blue"
-        android:fillType="evenOdd" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_link.xml b/app/src/main/res/drawable/ic_composer_link.xml
deleted file mode 100644
index be76286af10f63eb0c7dac33ec22a30781103e52..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_link.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M22.566,16.151L23.101,15.616C24.577,14.14 26.956,14.126 28.415,15.585C29.874,17.044 29.86,19.423 28.383,20.899L25.844,23.438C24.368,24.915 21.989,24.929 20.53,23.47M21.434,27.849L20.899,28.383C19.423,29.86 17.044,29.874 15.585,28.415C14.126,26.956 14.14,24.577 15.616,23.101L18.156,20.562C19.632,19.086 22.011,19.071 23.47,20.53"
-        android:strokeWidth="1.5"
-        android:strokeColor="@color/blue"
-        android:strokeLineCap="round" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_numbered_list.xml b/app/src/main/res/drawable/ic_composer_numbered_list.xml
deleted file mode 100644
index 5690e2de91efcec7eb129bfcf564f3139882153d..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_numbered_list.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:pathData="m14.5,20h-2c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5h1.3l-1.68,1.96C12.04,23.05 12,23.17 12,23.28v0.22c0,0.28 0.22,0.5 0.5,0.5h2C14.78,24 15,23.78 15,23.5 15,23.22 14.78,23 14.5,23h-1.3l1.68,-1.96C14.96,20.95 15,20.83 15,20.72V20.5C15,20.22 14.78,20 14.5,20Z"
-        android:fillColor="@color/blue" />
-    <path
-        android:pathData="M12.5,15H13v2.5c0,0.28 0.22,0.5 0.5,0.5 0.28,0 0.5,-0.22 0.5,-0.5v-3C14,14.22 13.78,14 13.5,14h-1c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5z"
-        android:fillColor="@color/blue" />
-    <path
-        android:pathData="m14.5,26h-2c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5H14v0.5h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5H14V29h-1.5c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5v-3C15,26.22 14.78,26 14.5,26Z"
-        android:fillColor="@color/blue" />
-    <path
-        android:pathData="M30,21H18c-0.55,0 -1,0.45 -1,1 0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1z"
-        android:fillColor="@color/blue" />
-    <path
-        android:pathData="M30,27H18c-0.55,0 -1,0.45 -1,1 0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1z"
-        android:fillColor="@color/blue" />
-    <path
-        android:pathData="m18,17h12c0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1H18c-0.55,0 -1,0.45 -1,1 0,0.55 0.45,1 1,1z"
-        android:fillColor="@color/blue" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_strikethrough.xml b/app/src/main/res/drawable/ic_composer_strikethrough.xml
deleted file mode 100644
index 593cd3aca18017d5ffca71a20b2905dc443def31..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_strikethrough.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <path
-        android:pathData="M24.897,17.154C24.235,15.821 22.876,15.21 21.374,15.372C19.05,15.622 18.44,17.423 18.722,18.592C19.032,19.872 20.046,20.37 21.839,20.826H29.92C30.517,20.826 31,21.351 31,22C31,22.648 30.517,23.174 29.92,23.174H14.08C13.483,23.174 13,22.648 13,22C13,21.351 13.483,20.826 14.08,20.826H17.355C17.041,20.377 16.791,19.839 16.633,19.189C16.003,16.581 17.554,13.424 21.16,13.036C23.285,12.807 25.615,13.661 26.798,16.038C27.081,16.608 26.886,17.32 26.361,17.629C25.836,17.937 25.181,17.725 24.897,17.154Z"
-        android:fillColor="@color/blue" />
-    <path
-        android:pathData="M25.427,25.13H27.67C27.888,26.306 27.721,27.56 27.05,28.632C26.114,30.125 24.37,31 21.985,31C18.076,31 16.279,28.584 15.912,26.986C15.768,26.357 16.12,25.72 16.698,25.563C17.277,25.406 17.863,25.788 18.008,26.417C18.119,26.902 19.002,28.652 21.985,28.652C23.907,28.652 24.854,27.965 25.264,27.31C25.642,26.707 25.708,25.909 25.427,25.13Z"
-        android:fillColor="@color/blue" />
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_underlined.xml b/app/src/main/res/drawable/ic_composer_underlined.xml
deleted file mode 100644
index c0b515adff45070dd208c65ef8ee2ebda6bfe451..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_underlined.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:tint="@color/menu_icon_color"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <group>
-        <clip-path android:pathData="M10,10h24v24h-24z" />
-        <path
-            android:fillColor="@color/blue"
-            android:pathData="M22.79,26.95C25.82,26.56 28,23.84 28,20.79V14.25C28,13.56 27.44,13 26.75,13C26.06,13 25.5,13.56 25.5,14.25V20.9C25.5,22.57 24.37,24.09 22.73,24.42C20.48,24.89 18.5,23.17 18.5,21V14.25C18.5,13.56 17.94,13 17.25,13C16.56,13 16,13.56 16,14.25V21C16,24.57 19.13,27.42 22.79,26.95ZM15,30C15,30.55 15.45,31 16,31H28C28.55,31 29,30.55 29,30C29,29.45 28.55,29 28,29H16C15.45,29 15,29.45 15,30Z" />
-    </group>
-</vector>
diff --git a/app/src/main/res/drawable/ic_composer_unindent.xml b/app/src/main/res/drawable/ic_composer_unindent.xml
deleted file mode 100644
index a4a7fc69a4890a0e380e051ffe4876d5125672b1..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_composer_unindent.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="44dp"
-    android:height="44dp"
-    android:tint="@color/menu_icon_color"
-    android:viewportWidth="44"
-    android:viewportHeight="44">
-    <group>
-        <clip-path android:pathData="M10,10h24v24h-24z" />
-        <path
-            android:fillColor="@color/blue"
-            android:pathData="M22,27H30C30.55,27 31,26.55 31,26C31,25.45 30.55,25 30,25H22C21.45,25 21,25.45 21,26C21,26.55 21.45,27 22,27ZM13.35,22.35L16.14,25.14C16.46,25.46 17,25.24 17,24.79V19.21C17,18.76 16.46,18.54 16.15,18.86L13.36,21.65C13.16,21.84 13.16,22.16 13.35,22.35ZM14,31H30C30.55,31 31,30.55 31,30C31,29.45 30.55,29 30,29H14C13.45,29 13,29.45 13,30C13,30.55 13.45,31 14,31ZM13,14C13,14.55 13.45,15 14,15H30C30.55,15 31,14.55 31,14C31,13.45 30.55,13 30,13H14C13.45,13 13,13.45 13,14ZM22,19H30C30.55,19 31,18.55 31,18C31,17.45 30.55,17 30,17H22C21.45,17 21,17.45 21,18C21,18.55 21.45,19 22,19ZM22,23H30C30.55,23 31,22.55 31,22C31,21.45 30.55,21 30,21H22C21.45,21 21,21.45 21,22C21,22.55 21.45,23 22,23Z" />
-    </group>
-</vector>
diff --git a/app/src/main/res/layout/list_item_style_bar.xml b/app/src/main/res/layout/list_item_style_bar.xml
deleted file mode 100644
index 4709beb7bf83c39e6c1878c96ffb76cf9687a82b..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/list_item_style_bar.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/cvOption"
-    android:layout_width="48dp"
-    android:layout_height="48dp"
-    android:clickable="true"
-    android:elevation="4dp"
-    android:focusable="true"
-    android:foreground="?selectableItemBackground"
-    app:cardCornerRadius="8dp"
-    app:cardUseCompatPadding="true">
-
-    <ImageView
-        android:id="@+id/ivIcon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:src="@drawable/ic_mention" />
-
-</androidx.cardview.widget.CardView>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index ed95017c76f6572d163340f7c993dc9ad6cc3b11..07d86d8a7e7d17a3fd38ce9ccd5251d9198e6d9d 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -10,11 +10,9 @@
     <color name="status_bar_color">#20111111</color>
 
     <color name="green">#34C759</color>
-    <color name="purple">#AF52DE</color>
     <color name="yellow">#FFCC00</color>
     <color name="orange">#FF9500</color>
     <color name="red">#FF3B30</color>
-    <color name="pink">#FF2D55</color>
     <color name="gray">#8E8E93</color>
     <color name="close_background">#80000000</color>
     <color name="highlight_color">#4D0E7AFE</color>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ab5bee724941d80d5211c56a9e22e48d95c04876..4e073536a5f31ded2d8192ba00c8317dd78f5720 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,7 +10,6 @@
     <string name="my_circles">My Circles</string>
     <string name="share">Share</string>
     <string name="fix">Fix</string>
-    <string name="followers">Followers</string>
     <string name="known_users">Known users</string>
     <string name="ignored_users">Ignored users</string>
     <string name="suggestions">Suggestions</string>
@@ -27,7 +26,6 @@
     <string name="requests_format">Requests %d</string>
     <string name="create_post">Create post</string>
     <string name="create_poll">Create poll</string>
-    <string name="send">Send</string>
     <string name="enter_your_message_here">Enter your message here</string>
     <string name="compressing">Compressing</string>
     <string name="encrypting">Encrypting</string>
@@ -187,7 +185,6 @@
     <string name="circles_empty_message">Create your first Circle</string>
     <string name="people_category_empty_message">%s will be shown here</string>
     <string name="creating_timeline">Creating timeline</string>
-    <string name="session">Session</string>
     <string name="help">Help</string>
     <string name="optional_request_message">Optional: Request message</string>
     <string name="media_storage">Media storage</string>
@@ -200,17 +197,6 @@
     <string name="ignored">Ignored</string>
 
     <!-- Rich text editor -->
-    <string name="rich_text_editor_format_bold">Apply bold format</string>
-    <string name="rich_text_editor_format_italic">Apply italic format</string>
-    <string name="rich_text_editor_format_strikethrough">Apply strikethrough format</string>
-    <string name="rich_text_editor_format_underline">Apply underline format</string>
-    <string name="rich_text_editor_link">Set link</string>
-    <string name="rich_text_editor_numbered_list">Toggle numbered list</string>
-    <string name="rich_text_editor_bullet_list">Toggle bullet list</string>
-    <string name="rich_text_editor_indent">Indent</string>
-    <string name="rich_text_editor_unindent">Unindent</string>
-    <string name="rich_text_editor_quote">Toggle quote</string>
-    <string name="rich_text_editor_code_block">Toggle code block</string>
     <string name="general">General</string>
     <string name="empty_media_storage_info">0 MB used</string>
     <string name="in_timeline_format">(in %1$s / %2$s)</string>
diff --git a/auth/build.gradle b/auth/build.gradle
index 55d1706ce6f1e0f3376360614ae55ef17df66c9e..43cca46bd6c164203eae60b620d57f538429a94b 100644
--- a/auth/build.gradle
+++ b/auth/build.gradle
@@ -87,7 +87,7 @@ dependencies {
     //Hilt
     implementation "com.google.dagger:hilt-android:$rootProject.ext.hilt_version"
     kapt "com.google.dagger:hilt-compiler:$rootProject.ext.hilt_version"
-    implementation "androidx.hilt:hilt-work:1.1.0"
+    implementation 'androidx.hilt:hilt-work:1.2.0'
 
     testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.5'
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsViewModel.kt
index 882340381ff3c82e886376dd36c745cd95e8c3be..3e43ea8df1b5352f394cf619e5bdbcc15f18bb83 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsViewModel.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsViewModel.kt
@@ -1,8 +1,13 @@
 package org.futo.circles.auth.feature.active_sessions
 
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.asLiveData
 import dagger.hilt.android.lifecycle.HiltViewModel
+import org.futo.circles.auth.model.ActiveSession
+import org.futo.circles.auth.model.ActiveSessionListItem
+import org.futo.circles.auth.model.SessionHeader
 import org.futo.circles.core.base.SingleEventLiveData
 import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.launchBg
@@ -13,18 +18,39 @@ class ActiveSessionsViewModel @Inject constructor(
     private val dataSource: ActiveSessionsDataSource
 ) : ViewModel() {
 
-    val activeSessionsLiveData = dataSource.getActiveSessionsFlow().asLiveData()
     val removeSessionLiveData = SingleEventLiveData<Response<Unit?>>()
     val resetKeysLiveData = SingleEventLiveData<Response<Unit?>>()
     val startReAuthEventLiveData = dataSource.startReAuthEventLiveData
 
+    private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet())
+
+    val activeSessionsLiveData = MediatorLiveData<List<ActiveSessionListItem>>().also {
+        it.addSource(loadingItemsIdsList) { loadingItemsValue ->
+            val currentList = it.value ?: emptyList()
+            it.postValue(
+                currentList.map { item ->
+                    when (item) {
+                        is ActiveSession -> item.copy(isLoading = loadingItemsValue.contains(item.id))
+                        is SessionHeader -> item
+                    }
+                }
+            )
+        }
+        it.addSource(dataSource.getActiveSessionsFlow().asLiveData()) { value ->
+            it.postValue(value)
+        }
+    }
+
+
     fun onSessionClicked(deviceId: String) {
         dataSource.toggleOptionsVisibilityFor(deviceId)
     }
 
     fun removeSession(deviceId: String) {
         launchBg {
+            toggleItemLoading(deviceId)
             val deactivateResult = dataSource.removeSession(deviceId)
+            toggleItemLoading(deviceId)
             removeSessionLiveData.postValue(deactivateResult)
         }
     }
@@ -35,4 +61,13 @@ class ActiveSessionsViewModel @Inject constructor(
             resetKeysLiveData.postValue(resetKeysResult)
         }
     }
+
+    private fun toggleItemLoading(id: String) {
+        val currentSet = loadingItemsIdsList.value?.toMutableSet() ?: return
+        val newLoadingSet = currentSet.apply {
+            if (this.contains(id)) remove(id)
+            else add(id)
+        }
+        loadingItemsIdsList.postValue(newLoadingSet)
+    }
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt
index aa1eb5d136b7b871956947ff24c789697dfb8584..a46ca87316da03f2b40ef1eeda5694a8420e7a05 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/workspace/data_source/ConfigureWorkspaceDataSource.kt
@@ -5,6 +5,7 @@ import org.futo.circles.core.feature.room.create.CreateRoomDataSource
 import org.futo.circles.core.feature.workspace.SpacesTreeAccountDataSource
 import org.futo.circles.core.model.CIRCLES_SPACE_ACCOUNT_DATA_KEY
 import org.futo.circles.core.model.CirclesRoom
+import org.futo.circles.core.model.PROFILE_SPACE_ACCOUNT_DATA_KEY
 import org.futo.circles.core.model.SharedCirclesSpace
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.utils.getAllJoinedCirclesRoomsAndSpaces
@@ -27,7 +28,9 @@ class ConfigureWorkspaceDataSource @Inject constructor(
 
     private suspend fun validateAndFixRelationInNeeded(roomId: String, room: CirclesRoom) {
         try {
-            getJoinedRoomById(roomId)?.let { validateRelations(room.parentAccountDataKey, it) }
+            getJoinedRoomById(roomId)?.let {
+                validateRelations(room.parentAccountDataKey, it, room.accountDataKey)
+            }
         } catch (_: Exception) {
             val parentRoomId =
                 room.parentAccountDataKey?.let { spacesTreeAccountDataSource.getRoomIdByKey(it) }
@@ -42,10 +45,14 @@ class ConfigureWorkspaceDataSource @Inject constructor(
             ?: throw IllegalArgumentException("No account data record for key $accountDataKey")
         val joinedRoom = getJoinedRoomById(roomId)
             ?: throw IllegalArgumentException("No joined room for id $roomId found")
-        validateRelations(room.parentAccountDataKey, joinedRoom)
+        validateRelations(room.parentAccountDataKey, joinedRoom, accountDataKey)
     }
 
-    private fun validateRelations(parentAccountDataKey: String?, joinedRoom: Room) {
+    private fun validateRelations(
+        parentAccountDataKey: String?,
+        joinedRoom: Room,
+        accountDataKey: String?
+    ) {
         val parentKey = parentAccountDataKey ?: return
         val parentRoomId =
             spacesTreeAccountDataSource.getRoomIdByKey(parentKey) ?: throw IllegalArgumentException(
@@ -58,7 +65,8 @@ class ConfigureWorkspaceDataSource @Inject constructor(
             ?.spaceSummary()?.spaceParents?.mapNotNull { it.parentId }
             ?.contains(parentRoomId) == true
 
-        if (!childHasRelationToParent)
+        //iOS app do not set this relation
+        if (!childHasRelationToParent && accountDataKey != PROFILE_SPACE_ACCOUNT_DATA_KEY)
             throw IllegalArgumentException("Missing child to parent relations")
 
         val parentHasRelationToChild = joinedParentRoom.asSpace()
diff --git a/auth/src/main/java/org/futo/circles/auth/model/ActiveSessionListItem.kt b/auth/src/main/java/org/futo/circles/auth/model/ActiveSessionListItem.kt
index 555d5483fd8b0ad9ae7b2a2aa426be6c349c1325..079abecffe94073f409b059b411af5645d3322a3 100644
--- a/auth/src/main/java/org/futo/circles/auth/model/ActiveSessionListItem.kt
+++ b/auth/src/main/java/org/futo/circles/auth/model/ActiveSessionListItem.kt
@@ -18,7 +18,8 @@ data class ActiveSession(
     val cryptoDeviceInfo: CryptoDeviceInfo,
     val canVerify: Boolean,
     val isResetKeysVisible: Boolean,
-    val isOptionsVisible: Boolean
+    val isOptionsVisible: Boolean,
+    val isLoading: Boolean = false
 ) : ActiveSessionListItem() {
     override val id: String = cryptoDeviceInfo.deviceId
 
diff --git a/auth/src/main/java/org/futo/circles/auth/view/ActiveSessionInfoView.kt b/auth/src/main/java/org/futo/circles/auth/view/ActiveSessionInfoView.kt
index e63080807e3b14bf47626653d21d3cf1a20d0e97..a7463cf0b5b0b392415499d5f43142e29ee91c9e 100644
--- a/auth/src/main/java/org/futo/circles/auth/view/ActiveSessionInfoView.kt
+++ b/auth/src/main/java/org/futo/circles/auth/view/ActiveSessionInfoView.kt
@@ -6,6 +6,7 @@ import android.view.LayoutInflater
 import androidx.constraintlayout.widget.ConstraintLayout
 import org.futo.circles.auth.databinding.ViewActiveSessionInfoBinding
 import org.futo.circles.auth.feature.active_sessions.list.ActiveSessionClickListener
+import org.futo.circles.auth.model.ActiveSession
 import org.futo.circles.core.extensions.setIsVisible
 
 class ActiveSessionInfoView(
@@ -32,17 +33,18 @@ class ActiveSessionInfoView(
     }
 
     fun setData(
-        activeSession: org.futo.circles.auth.model.ActiveSession,
+        activeSession: ActiveSession,
         listener: ActiveSessionClickListener
     ) {
         deviceId = activeSession.id
         activeSessionClickListener = listener
         with(binding) {
+            vLoading.setIsVisible(activeSession.isLoading)
             tvFingerprint.text = activeSession.cryptoDeviceInfo.fingerprint() ?: ""
             tvPublicKey.text = activeSession.cryptoDeviceInfo.identityKey() ?: ""
-            btnVerify.setIsVisible(activeSession.canVerify)
-            btnRemove.setIsVisible(!activeSession.isCurrentSession())
-            btnResetKeys.setIsVisible(activeSession.isResetKeysVisible)
+            btnVerify.setIsVisible(activeSession.canVerify && !activeSession.isLoading)
+            btnRemove.setIsVisible(!activeSession.isCurrentSession() && !activeSession.isLoading)
+            btnResetKeys.setIsVisible(activeSession.isResetKeysVisible && !activeSession.isLoading)
         }
     }
 }
\ No newline at end of file
diff --git a/auth/src/main/res/layout/view_active_session_info.xml b/auth/src/main/res/layout/view_active_session_info.xml
index 18adfc80e412a1f098233b3af8ead7590278755e..d0b08721cf66730fa665ca01cc83ec880a78b2e8 100644
--- a/auth/src/main/res/layout/view_active_session_info.xml
+++ b/auth/src/main/res/layout/view_active_session_info.xml
@@ -97,4 +97,14 @@
         app:layout_constraintStart_toEndOf="@id/btnRemove"
         app:layout_constraintTop_toBottomOf="@+id/tvPublicKey" />
 
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:visibility="gone"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tvPublicKey" />
+
 </merge>
\ No newline at end of file
diff --git a/auth/src/main/res/values/color.xml b/auth/src/main/res/values/color.xml
index 49fde422f59f7ab5135a3cd34d5745489dff9408..e0ba5413a81aea21a0b06324bed3da07ef238805 100644
--- a/auth/src/main/res/values/color.xml
+++ b/auth/src/main/res/values/color.xml
@@ -7,7 +7,5 @@
     <color name="red">#FF3B30</color>
     <color name="green">#34C759</color>
     <color name="teal_700">#FF018786</color>
-    <color name="purple">#AF52DE</color>
-    <color name="pink">#FF2D55</color>
 
 </resources>
\ No newline at end of file
diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml
index a0368d8b476996342e9b164c2d473eccd944ca65..d7879e36f2ff17a85793bb7f067f4dc0f44c903e 100644
--- a/auth/src/main/res/values/strings.xml
+++ b/auth/src/main/res/values/strings.xml
@@ -6,18 +6,14 @@
     <string name="b_param_is_missing">B param is missing</string>
     <string name="initial_device_name">FUTO Circles (Android)</string>
     <string name="initial_sync">Initial sync</string>
-    <string name="not_found_login_flow_for_user">Log In flow for user not found</string>
+    <string name="session_sync">Session sync</string>
     <string name="unsupported_login_method">Unsupported login method</string>
     <string name="discard_current_auth_progress">Discard current auth progress?</string>
     <string name="set_password">Set password</string>
     <string name="log_in">Log In</string>
     <string name="wrong_signup_config">Wrong signup config!</string>
-    <string name="us_server_format"><![CDATA[<b>US</b> - (%s)]]></string>
-    <string name="eu_server_format"><![CDATA[<b>EU</b> - (%s)]]></string>
-    <string name="sign_up_using_active_subscription">Sign Up using your active subscription</string>
     <string name="sign_up">Sign Up</string>
     <string name="sign_up_stage_subtitle_format">Stage %1$d of %2$d</string>
-    <string name="no_backup_message">Keys backup not found</string>
     <string name="username_can_not_be_empty">Username can not be empty.</string>
     <string name="confirm_auth">Confirm auth</string>
     <string name="email">Email</string>
@@ -67,7 +63,6 @@
     <string name="save">Save</string>
     <string name="skip">Skip</string>
     <string name="subscriptions">Subscriptions</string>
-    <string name="subscription">Subscription</string>
     <string name="manage_subscription">Manage subscription</string>
     <string name="enter_your_username">Enter your username</string>
     <string name="set_username">Set username</string>
@@ -83,7 +78,6 @@
     <string name="upload_recovery_key_file">Upload Recovery Key file</string>
     <string name="restore">Restore</string>
     <string name="validate_your_email">Validate your email</string>
-    <string name="not_supported_navigation_event">Not supported navigation event</string>
     <string name="feature_not_supported">Feature is not supported</string>
     <string name="service_unavailable">Service unavailable</string>
     <string name="item_unavailable">Item is unavailable</string>
@@ -111,7 +105,6 @@
     <string name="other_sessions">Other sessions</string>
     <string name="invalid_auth">Invalid auth</string>
     <string name="scan_with_one_of_devices_message">Scan QR code with one of your devices to finish verification</string>
-    <string name="cross_signed">cross signed</string>
     <string name="waiting_for_other_device_verification">Waiting for other device to start verification</string>
     <string name="session_verified">Session verified</string>
     <string name="verification_canceled">Verification canceled</string>
diff --git a/build.gradle b/build.gradle
index 6368cdbe4abc3cf2bade48b56368e4e203c96be1..cdbde14b895359cd37691510381d14dc2a9ae37e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,7 +3,7 @@ buildscript {
         sdk_version = 34
         min_sdk_version = 24
         androidx_nav_version = '2.7.7'
-        hilt_version = '2.50'
+        hilt_version = '2.51'
         modules_version = "1.0.9"
         modules_groupId = "org.futo.gitlab.circles"
     }
diff --git a/core/build.gradle b/core/build.gradle
index 25be662b05a876935384d957d7f90ed66ef9629b..ee51d232f5218600ef14095c64e880ef16faf0df 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -99,6 +99,7 @@ dependencies {
     implementation 'jp.wasabeef:glide-transformations:4.3.0'
 
     //Webp animations
+    //noinspection GradleDependency
     api 'com.github.penfeizhou.android.animation:glide-plugin:2.28.0'
 
     //QR
@@ -111,7 +112,7 @@ dependencies {
     api "io.noties.markwon:ext-strikethrough:$markwon_version"
     api "io.noties.markwon:ext-tasklist:$markwon_version"
 
-    api 'io.element.android:wysiwyg:2.29.0'
+    api 'io.element.android:wysiwyg:2.30.0'
 
     //Shake detection
     implementation 'com.squareup:seismic:1.0.3'
diff --git a/core/src/main/java/org/futo/circles/core/extensions/ViewExtensions.kt b/core/src/main/java/org/futo/circles/core/extensions/ViewExtensions.kt
index e66b2f962304b3c34ed197bc10ba11c50b9e6eee..17090ae2b158298537af7a9209e799c9e98b40ec 100644
--- a/core/src/main/java/org/futo/circles/core/extensions/ViewExtensions.kt
+++ b/core/src/main/java/org/futo/circles/core/extensions/ViewExtensions.kt
@@ -21,6 +21,10 @@ fun View.gone() {
     visibility = View.GONE
 }
 
+fun View.invisible() {
+    visibility = View.INVISIBLE
+}
+
 fun View.setIsVisible(isVisible: Boolean) {
     visibility = if (isVisible) View.VISIBLE else View.GONE
 }
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/invites/InvitesViewModel.kt b/core/src/main/java/org/futo/circles/core/feature/room/invites/InvitesViewModel.kt
index eafb2308fca561599efef7c1e5c35387b1cdacba..aae3081014671d76c3a0f39ee74ca01be9640f05 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/invites/InvitesViewModel.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/invites/InvitesViewModel.kt
@@ -1,5 +1,7 @@
 package org.futo.circles.core.feature.room.invites
 
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.asLiveData
@@ -11,7 +13,12 @@ import org.futo.circles.core.extensions.launchBg
 import org.futo.circles.core.feature.room.invite.ManageInviteRequestsDataSource
 import org.futo.circles.core.feature.workspace.SharedCircleDataSource
 import org.futo.circles.core.model.CircleRoomTypeArg
+import org.futo.circles.core.model.ConnectionInviteListItem
+import org.futo.circles.core.model.FollowRequestListItem
+import org.futo.circles.core.model.InviteHeader
+import org.futo.circles.core.model.InviteListItem
 import org.futo.circles.core.model.InviteTypeArg
+import org.futo.circles.core.model.RoomInviteListItem
 import javax.inject.Inject
 
 @HiltViewModel
@@ -25,29 +32,57 @@ class InvitesViewModel @Inject constructor(
     private val inviteType: InviteTypeArg = savedStateHandle.getOrThrow("type")
 
     val inviteResultLiveData = SingleEventLiveData<Response<Unit?>>()
-    val invitesLiveData = dataSource.getInvitesFlow(inviteType).asLiveData()
+    private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet())
+    val invitesLiveData = MediatorLiveData<List<InviteListItem>>().also {
+        it.addSource(loadingItemsIdsList) { loadingItemsValue ->
+            val currentList = it.value ?: emptyList()
+            it.postValue(currentList.map { item ->
+                when (item) {
+                    is ConnectionInviteListItem -> item.copy(
+                        isLoading = loadingItemsValue.contains(item.id)
+                    )
+
+                    is FollowRequestListItem -> item.copy(
+                        isLoading = loadingItemsValue.contains(item.id)
+                    )
+
+                    is RoomInviteListItem -> item.copy(
+                        isLoading = loadingItemsValue.contains(item.id)
+                    )
+
+                    is InviteHeader -> item
+                }
+            })
+        }
+        it.addSource(dataSource.getInvitesFlow(inviteType).asLiveData()) { value ->
+            it.postValue(value)
+        }
+    }
 
     fun getInviteType() = inviteType
 
     fun rejectRoomInvite(roomId: String) {
         launchBg {
+            toggleItemLoading(roomId)
             val result = manageInviteRequestsDataSource.rejectInvite(roomId)
-            inviteResultLiveData.postValue(result)
+            postInviteResult(result, roomId)
         }
     }
 
     fun acceptRoomInvite(roomId: String, roomType: CircleRoomTypeArg) {
         launchBg {
+            toggleItemLoading(roomId)
             val result = manageInviteRequestsDataSource.acceptInvite(roomId, roomType)
-            inviteResultLiveData.postValue(result)
+            postInviteResult(result, roomId)
         }
     }
 
     fun onFollowRequestAnswered(userId: String, accepted: Boolean) {
         launchBg {
+            toggleItemLoading(userId)
             val result = if (accepted) dataSource.acceptFollowRequest(userId)
             else dataSource.declineFollowRequest(userId)
-            inviteResultLiveData.postValue(result)
+            postInviteResult(result, userId)
         }
     }
 
@@ -58,11 +93,25 @@ class InvitesViewModel @Inject constructor(
     fun onConnectionInviteAnswered(roomId: String, accepted: Boolean) {
         if (accepted)
             launchBg {
-               val result =  sharedCircleDataSource.acceptSharedCircleInvite(roomId)
-                inviteResultLiveData.postValue(result)
+                toggleItemLoading(roomId)
+                val result = sharedCircleDataSource.acceptSharedCircleInvite(roomId)
+                postInviteResult(result, roomId)
             }
         else rejectRoomInvite(roomId)
     }
 
+    private fun postInviteResult(result: Response<Unit?>, id: String) {
+        inviteResultLiveData.postValue(result)
+        toggleItemLoading(id)
+    }
+
+    private fun toggleItemLoading(id: String) {
+        val currentSet = loadingItemsIdsList.value?.toMutableSet() ?: return
+        val newLoadingSet = currentSet.apply {
+            if (this.contains(id)) remove(id)
+            else add(id)
+        }
+        loadingItemsIdsList.postValue(newLoadingSet)
+    }
 
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/invites/list/InvitesViewHolder.kt b/core/src/main/java/org/futo/circles/core/feature/room/invites/list/InvitesViewHolder.kt
index ce4878c3258a8a24b27122fba1011b24dbb92d95..24b4c012e83f602fb8c28311fa3f733024365c80 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/invites/list/InvitesViewHolder.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/invites/list/InvitesViewHolder.kt
@@ -49,6 +49,7 @@ class InvitedGroupViewHolder(
         if (data !is RoomInviteListItem) return
 
         with(binding) {
+            setLoading(data.isLoading)
             ivGroup.loadRoomProfileIcon(
                 data.info.avatarUrl,
                 data.info.title,
@@ -63,6 +64,14 @@ class InvitedGroupViewHolder(
             )
         }
     }
+
+    private fun setLoading(isLoading: Boolean) {
+        with(binding) {
+            vLoading.setIsVisible(isLoading)
+            btnAccept.setIsVisible(!isLoading)
+            btnDecline.setIsVisible(!isLoading)
+        }
+    }
 }
 
 class InvitedCircleViewHolder(
@@ -85,6 +94,7 @@ class InvitedCircleViewHolder(
         if (data !is RoomInviteListItem) return
 
         with(binding) {
+            setLoading(data.isLoading)
             tvShowProfileImage.setIsVisible(data.shouldBlurIcon)
             ivCircle.loadRoomProfileIcon(
                 data.info.avatarUrl,
@@ -99,6 +109,14 @@ class InvitedCircleViewHolder(
                 )
         }
     }
+
+    private fun setLoading(isLoading: Boolean) {
+        with(binding) {
+            vLoading.setIsVisible(isLoading)
+            btnAccept.setIsVisible(!isLoading)
+            btnDecline.setIsVisible(!isLoading)
+        }
+    }
 }
 
 class InvitedGalleryViewHolder(
@@ -121,6 +139,7 @@ class InvitedGalleryViewHolder(
         if (data !is RoomInviteListItem) return
 
         with(binding) {
+            setLoading(data.isLoading)
             tvGalleryTitle.text = data.info.title
             ivGallery.loadRoomProfileIcon(
                 data.info.avatarUrl,
@@ -131,6 +150,14 @@ class InvitedGalleryViewHolder(
             tvInviterName.text = context.getString(R.string.invited_by_format, data.inviterName)
         }
     }
+
+    private fun setLoading(isLoading: Boolean) {
+        with(binding) {
+            vLoading.setIsVisible(isLoading)
+            btnAccept.setIsVisible(!isLoading)
+            btnDecline.setIsVisible(!isLoading)
+        }
+    }
 }
 
 class FollowRequestViewHolder(
@@ -148,8 +175,10 @@ class FollowRequestViewHolder(
     }
 
     override fun bind(data: InviteListItem) {
-        val user = (data as? FollowRequestListItem)?.user ?: return
-        bindUser(user)
+        if (data !is FollowRequestListItem) return
+
+        setLoading(data.isLoading)
+        bindUser(data.user)
         binding.tvReasonMessage.apply {
             setIsVisible(data.reasonMessage != null)
             text = data.reasonMessage
@@ -162,6 +191,14 @@ class FollowRequestViewHolder(
             ivUserImage.loadUserProfileIcon(user.avatarUrl, user.id)
         }
     }
+
+    private fun setLoading(isLoading: Boolean) {
+        with(binding) {
+            vLoading.setIsVisible(isLoading)
+            btnAccept.setIsVisible(!isLoading)
+            btnDecline.setIsVisible(!isLoading)
+        }
+    }
 }
 
 class ConnectionInviteViewHolder(
@@ -179,8 +216,10 @@ class ConnectionInviteViewHolder(
     }
 
     override fun bind(data: InviteListItem) {
-        val user = (data as? ConnectionInviteListItem)?.user ?: return
-        bindUser(user)
+        if (data !is ConnectionInviteListItem) return
+
+        setLoading(data.isLoading)
+        bindUser(data.user)
     }
 
     private fun bindUser(user: CirclesUserSummary) {
@@ -189,6 +228,14 @@ class ConnectionInviteViewHolder(
             ivUserImage.loadUserProfileIcon(user.avatarUrl, user.id)
         }
     }
+
+    private fun setLoading(isLoading: Boolean) {
+        with(binding) {
+            vLoading.setIsVisible(isLoading)
+            btnAccept.setIsVisible(!isLoading)
+            btnDecline.setIsVisible(!isLoading)
+        }
+    }
 }
 
 class InviteHeaderViewHolder(
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt
index fc6c48a179e3b0290cd1f83f9a174b6d5e048ec8..d979e513cdae1a5a57cbe2558cf461ae71f249c6 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt
@@ -1,5 +1,7 @@
 package org.futo.circles.core.feature.room.knoks
 
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -20,18 +22,45 @@ class KnockRequestViewModel @Inject constructor(
 
     private val roomId: String = savedStateHandle.getOrThrow("roomId")
 
-    val knockRequestsLiveData = knockRequestsDataSource.getKnockRequestsListItemsLiveData(roomId)
     val inviteResultLiveData = SingleEventLiveData<Response<Unit?>>()
+    private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet())
+
+    val knockRequestsLiveData = MediatorLiveData<List<KnockRequestListItem>>().also {
+        it.addSource(loadingItemsIdsList) { loadingItemsValue ->
+            val currentList = it.value ?: emptyList()
+            it.postValue(currentList.map { item ->
+                item.copy(isLoading = loadingItemsValue.contains(item.id))
+            })
+        }
+        it.addSource(knockRequestsDataSource.getKnockRequestsListItemsLiveData(roomId)) { value ->
+            it.postValue(value)
+        }
+    }
 
     fun inviteUser(user: KnockRequestListItem) {
         launchBg {
+            toggleItemLoading(user.id)
             val result = manageInviteRequestsDataSource.inviteUser(roomId, user.requesterId)
             inviteResultLiveData.postValue(result)
+            toggleItemLoading(user.id)
         }
     }
 
     fun kickUser(user: KnockRequestListItem) {
-        launchBg { manageInviteRequestsDataSource.kickUser(roomId, user.requesterId) }
+        launchBg {
+            toggleItemLoading(user.id)
+            manageInviteRequestsDataSource.kickUser(roomId, user.requesterId)
+            toggleItemLoading(user.id)
+        }
+    }
+
+    private fun toggleItemLoading(id: String) {
+        val currentSet = loadingItemsIdsList.value?.toMutableSet() ?: return
+        val newLoadingSet = currentSet.apply {
+            if (this.contains(id)) remove(id)
+            else add(id)
+        }
+        loadingItemsIdsList.postValue(newLoadingSet)
     }
 
 }
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt
index 9df217009759d90457fcf31e321cefb377c984e1..47767ddaab6ed832d27f801f5b17593f7b60eaa2 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt
@@ -1,6 +1,7 @@
 package org.futo.circles.core.feature.room.knoks
 
 import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.asFlow
 import androidx.lifecycle.asLiveData
 import androidx.lifecycle.map
@@ -27,7 +28,7 @@ class KnockRequestsDataSource @Inject constructor() {
 
     fun getKnockRequestsListItemsLiveData(roomId: String) = getKnockRequestLiveData(roomId)?.map {
         it.map { user -> user.toKnockRequestListItem(roomId) }
-    }
+    } ?: MutableLiveData(emptyList())
 
     fun getKnockRequestCountLiveDataForCurrentUserInRoom(roomId: String): LiveData<Int> {
         val session = MatrixSessionProvider.getSessionOrThrow()
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt
index 03b2e2784d0bceb2069b953a842b44433e6ca86d..35eaf04c8d8f4189006dd023e8e3fa9f4c9f27b1 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt
@@ -50,7 +50,7 @@ class KnockRequestsDialogFragment :
 
     private fun setupObservers() {
         viewModel.inviteResultLiveData.observeResponse(this)
-        viewModel.knockRequestsLiveData?.observeData(this) {
+        viewModel.knockRequestsLiveData.observeData(this) {
             knocksListAdapter.submitList(it)
         }
     }
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt
index c0634a69700050b11e5cd67d8d19e84bbf8cda08..d505094f84f6756e9a2edcd13703268086a25b58 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt
@@ -25,10 +25,21 @@ class KnockRequestViewHolder(
     }
 
     fun bind(data: KnockRequestListItem) {
-        binding.tvReason.apply {
-            setIsVisible(!data.message.isNullOrBlank())
-            text = data.message
+        with(binding) {
+            setLoading(data.isLoading)
+            tvReason.apply {
+                setIsVisible(!data.message.isNullOrBlank())
+                text = data.message
+            }
+            vUserLayout.bind(data.toCircleUser())
+        }
+    }
+
+    private fun setLoading(isLoading: Boolean) {
+        with(binding) {
+            vLoading.setIsVisible(isLoading)
+            btnInvite.setIsVisible(!isLoading)
+            btnDecline.setIsVisible(!isLoading)
         }
-        binding.vUserLayout.bind(data.toCircleUser())
     }
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt b/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt
index 59ed5252535c7e96948c44c7c2e16d8af83b2d00..b35cd9e37fcdf3f79494dfe7b5f4955457cd93bf 100644
--- a/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt
@@ -13,6 +13,7 @@ import org.futo.circles.core.base.NetworkObserver
 import org.futo.circles.core.base.fragment.BaseFullscreenDialogFragment
 import org.futo.circles.core.databinding.DialogFragmentUserBinding
 import org.futo.circles.core.extensions.gone
+import org.futo.circles.core.extensions.invisible
 import org.futo.circles.core.extensions.loadUserProfileIcon
 import org.futo.circles.core.extensions.notEmptyDisplayName
 import org.futo.circles.core.extensions.observeData
@@ -20,8 +21,10 @@ import org.futo.circles.core.extensions.observeResponse
 import org.futo.circles.core.extensions.onBackPressed
 import org.futo.circles.core.extensions.setEnabledChildren
 import org.futo.circles.core.extensions.setIsVisible
+import org.futo.circles.core.extensions.showError
 import org.futo.circles.core.extensions.showNoInternetConnection
 import org.futo.circles.core.extensions.showSuccess
+import org.futo.circles.core.extensions.visible
 import org.futo.circles.core.extensions.withConfirmation
 import org.futo.circles.core.feature.user.list.UsersCirclesAdapter
 import org.futo.circles.core.model.IgnoreUser
@@ -71,7 +74,11 @@ class UserDialogFragment : BaseFullscreenDialogFragment(DialogFragmentUserBindin
         }
         binding.btnInviteToConnect.apply {
             setIsVisible(!viewModel.isUserMyFollower())
-            setOnClickListener { viewModel.inviteToMySharedCircle() }
+            setOnClickListener {
+                binding.vInviteToConnectLoading.visible()
+                binding.btnInviteToConnect.invisible()
+                viewModel.inviteToMySharedCircle()
+            }
         }
     }
 
@@ -113,16 +120,25 @@ class UserDialogFragment : BaseFullscreenDialogFragment(DialogFragmentUserBindin
             }
         }
         viewModel.userLiveData.observeData(this) { setupUserInfo(it) }
-        viewModel.timelineLiveDataLiveData.observeData(this) {
+        viewModel.usersTimelinesLiveData.observeData(this) {
             usersCirclesAdapter.submitList(it)
         }
         viewModel.requestFollowLiveData.observeResponse(this,
             success = { showSuccess(getString(R.string.request_sent)) })
+
         viewModel.inviteToConnectLiveData.observeResponse(this,
             success = {
                 showSuccess(getString(R.string.request_sent))
                 binding.btnInviteToConnect.gone()
-            })
+            },
+            error = {
+                binding.btnInviteToConnect.visible()
+                showError(it)
+            },
+            onRequestInvoked = {
+                binding.vInviteToConnectLoading.gone()
+            }
+        )
         viewModel.ignoreUserLiveData.observeResponse(this,
             success = {
                 context?.let { showSuccess(it.getString(R.string.user_ignored)) }
diff --git a/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt b/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt
index 36ecdbea7bbeea38eb1eecd1c34e1f7bfd8c142c..e3ba56c33f0e85e86032d617521f26de5d0f3f56 100644
--- a/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt
@@ -1,5 +1,6 @@
 package org.futo.circles.core.feature.user
 
+import androidx.lifecycle.MediatorLiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
@@ -15,7 +16,9 @@ import org.futo.circles.core.extensions.launchUi
 import org.futo.circles.core.feature.room.RoomRelationsBuilder
 import org.futo.circles.core.feature.room.invite.ManageInviteRequestsDataSource
 import org.futo.circles.core.feature.workspace.SharedCircleDataSource
+import org.futo.circles.core.model.TimelineHeaderItem
 import org.futo.circles.core.model.TimelineListItem
+import org.futo.circles.core.model.TimelineRoomListItem
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.matrix.android.sdk.api.session.getRoom
 import javax.inject.Inject
@@ -34,7 +37,7 @@ class UserViewModel @Inject constructor(
     private val profileRoomId = sharedCircleDataSource.getSharedCirclesSpaceId() ?: ""
 
     val userLiveData = userDataSource.userLiveData
-    val timelineLiveDataLiveData = MutableLiveData<List<TimelineListItem>>()
+
     val requestFollowLiveData = SingleEventLiveData<Response<Unit?>>()
     val inviteToConnectLiveData = SingleEventLiveData<Response<Unit?>>()
     val ignoreUserLiveData = SingleEventLiveData<Response<Unit?>>()
@@ -44,6 +47,29 @@ class UserViewModel @Inject constructor(
         it.firstOrNull { it.userId == userId } != null
     }
 
+    private val timelineLiveData = MutableLiveData<List<TimelineListItem>>()
+    private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet())
+
+    val usersTimelinesLiveData = MediatorLiveData<List<TimelineListItem>>().also {
+        it.addSource(loadingItemsIdsList) { loadingItemsValue ->
+            val currentList = it.value ?: emptyList()
+            it.postValue(
+                currentList.map { item ->
+                    when (item) {
+                        is TimelineRoomListItem -> item.copy(
+                            isLoading = loadingItemsValue.contains(item.id)
+                        )
+
+                        is TimelineHeaderItem -> item
+                    }
+                }
+            )
+        }
+        it.addSource(timelineLiveData) { value ->
+            it.postValue(value)
+        }
+    }
+
     init {
         getUsersTimelines()
     }
@@ -51,16 +77,18 @@ class UserViewModel @Inject constructor(
     private fun getUsersTimelines() {
         launchUi {
             userDataSource.getTimelinesFlow().collectLatest {
-                timelineLiveDataLiveData.postValue(it)
+                timelineLiveData.postValue(it)
             }
         }
     }
 
     fun requestFollowTimeline(timelineId: String) {
         launchBg {
+            toggleItemLoading(timelineId)
             val result = createResult {
                 MatrixSessionProvider.currentSession?.roomService()?.knock(timelineId)
             }
+            toggleItemLoading(timelineId)
             requestFollowLiveData.postValue(result)
         }
     }
@@ -68,8 +96,10 @@ class UserViewModel @Inject constructor(
     fun unFollowTimeline(timelineId: String) {
         launchBg {
             createResult {
+                toggleItemLoading(timelineId)
                 roomRelationsBuilder.removeFromAllParents(timelineId)
                 MatrixSessionProvider.currentSession?.roomService()?.leaveRoom(timelineId)
+                toggleItemLoading(timelineId)
             }
         }
     }
@@ -109,4 +139,13 @@ class UserViewModel @Inject constructor(
         }
     }
 
+    private fun toggleItemLoading(id: String) {
+        val currentSet = loadingItemsIdsList.value?.toMutableSet() ?: return
+        val newLoadingSet = currentSet.apply {
+            if (this.contains(id)) remove(id)
+            else add(id)
+        }
+        loadingItemsIdsList.postValue(newLoadingSet)
+    }
+
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt b/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt
index a9158a2cb0260d351dd8f438e7947768c8b0fb1e..543077234d857f84103f421021047c3dfd41320b 100644
--- a/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt
@@ -39,8 +39,9 @@ class UsersTimelineRoomViewHolder(
         with(binding) {
             tvTimelineName.text = data.info.title
             ivTimelineImage.loadRoomProfileIcon(data.info.avatarUrl, data.info.title)
-            btnFollow.setIsVisible(!data.isJoined)
-            btnUnFollow.setIsVisible(data.isJoined)
+            vLoading.setIsVisible(data.isLoading)
+            btnFollow.setIsVisible(!data.isJoined && !data.isLoading)
+            btnUnFollow.setIsVisible(data.isJoined && !data.isLoading)
         }
     }
 }
diff --git a/core/src/main/java/org/futo/circles/core/model/InviteListItem.kt b/core/src/main/java/org/futo/circles/core/model/InviteListItem.kt
index 7cd4a690ab9cd53b2b134e99c83132c364d5b7de..be79cb77faac4b4bcba3150e667ba29ff446c2af 100644
--- a/core/src/main/java/org/futo/circles/core/model/InviteListItem.kt
+++ b/core/src/main/java/org/futo/circles/core/model/InviteListItem.kt
@@ -28,17 +28,20 @@ data class RoomInviteListItem(
     val info: RoomInfo,
     val isEncrypted: Boolean,
     val inviterName: String,
-    val shouldBlurIcon: Boolean
+    val shouldBlurIcon: Boolean,
+    val isLoading: Boolean = false
 ) : InviteListItem(roomId)
 
 data class FollowRequestListItem(
     val user: CirclesUserSummary,
-    val reasonMessage: String?
+    val reasonMessage: String?,
+    val isLoading: Boolean = false
 ) : InviteListItem(user.id)
 
 data class ConnectionInviteListItem(
     val roomId: String,
     val user: CirclesUserSummary,
+    val isLoading: Boolean = false
 ) : InviteListItem(roomId)
 
 fun RoomSummary.toRoomInviteListItem(roomType: CircleRoomTypeArg, shouldBlurIcon: Boolean) =
diff --git a/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt b/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt
index 4b7becdc89e219ce92754701ce590cb5b6b570b6..e3efa753ed8212de624a6a6fb5e81dadf51c0e6e 100644
--- a/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt
+++ b/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt
@@ -6,7 +6,8 @@ data class KnockRequestListItem(
     val requesterId: String,
     val requesterName: String,
     val requesterAvatarUrl: String?,
-    val message: String?
+    val message: String?,
+    val isLoading: Boolean = false
 ) : IdEntity<String> {
     override val id: String = requesterId
 }
diff --git a/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt b/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt
index 8c14a18deab25b56bea9d285a3bba4bfd458376f..54368d5782e641fd077e984d3cf0c1cc7ad284c7 100644
--- a/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt
+++ b/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt
@@ -23,7 +23,8 @@ data class TimelineHeaderItem(
 data class TimelineRoomListItem(
     override val id: String,
     val info: RoomInfo,
-    val isJoined: Boolean
+    val isJoined: Boolean,
+    val isLoading: Boolean = false
 ) : TimelineListItem()
 
 fun RoomSummary.toTimelineRoomListItem() = TimelineRoomListItem(
diff --git a/core/src/main/java/org/futo/circles/core/utils/MatrixUtils.kt b/core/src/main/java/org/futo/circles/core/utils/MatrixUtils.kt
index fa57f8681f2b7c604bca3af4173d18ed955f8664..1add9d8ea62384afdc80699b69d77b0a0ad11554 100644
--- a/core/src/main/java/org/futo/circles/core/utils/MatrixUtils.kt
+++ b/core/src/main/java/org/futo/circles/core/utils/MatrixUtils.kt
@@ -22,6 +22,12 @@ private val roomTypes = listOf(
     GROUP_TYPE
 )
 
+val circlesRoomsTypes = listOf(
+    GALLERY_TYPE,
+    TIMELINE_TYPE,
+    GROUP_TYPE
+)
+
 private fun getRoomsLiveDataWithType(
     type: String,
     membershipFilter: List<Membership> = Membership.activeMemberships()
diff --git a/core/src/main/res/layout/dialog_fragment_user.xml b/core/src/main/res/layout/dialog_fragment_user.xml
index f0e8b2bdd3326b0b462a46bafd315e3db3e367a1..9cd6eb96ee7992c651779c962e0a771fdb917a9d 100644
--- a/core/src/main/res/layout/dialog_fragment_user.xml
+++ b/core/src/main/res/layout/dialog_fragment_user.xml
@@ -86,6 +86,18 @@
         tools:visibility="visible" />
 
 
+    <ProgressBar
+        android:id="@+id/vInviteToConnectLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginTop="8dp"
+        android:visibility="gone"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tvUserId" />
+
+
     <View
         android:id="@+id/divider"
         android:layout_width="0dp"
diff --git a/core/src/main/res/layout/list_item_connection_invite.xml b/core/src/main/res/layout/list_item_connection_invite.xml
index 1e9d9a3718c80298b10a6da164b3cf8106cb96ea..efcf47b6c62bc2266e2489ca4a14f3ef0069edc9 100644
--- a/core/src/main/res/layout/list_item_connection_invite.xml
+++ b/core/src/main/res/layout/list_item_connection_invite.xml
@@ -47,7 +47,7 @@
         app:layout_constraintStart_toStartOf="@id/tvUserName"
         app:layout_constraintTop_toBottomOf="@id/tvUserName" />
 
-    
+
     <com.google.android.material.button.MaterialButton
         android:id="@+id/btnAccept"
         style="@style/AccentButtonStyle"
@@ -78,4 +78,17 @@
         app:layout_constraintStart_toEndOf="@id/btnAccept"
         app:layout_constraintTop_toTopOf="@id/btnAccept" />
 
+
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginTop="4dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/ivUserImage"
+        app:layout_constraintTop_toBottomOf="@+id/tvInvitesToConnect" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_invited_circle.xml b/core/src/main/res/layout/list_item_invited_circle.xml
index cc1d807904206e73c300bcb23db0cd5a1132bd7c..f3d478ff9c55891ef8eff1a0605c012f78f30a35 100644
--- a/core/src/main/res/layout/list_item_invited_circle.xml
+++ b/core/src/main/res/layout/list_item_invited_circle.xml
@@ -70,6 +70,7 @@
         app:layout_constraintTop_toBottomOf="@id/tvCircleTitle"
         tools:text="texsdt" />
 
+
     <com.google.android.material.button.MaterialButton
         android:id="@+id/btnAccept"
         style="@style/AccentButtonStyle"
@@ -97,4 +98,16 @@
         app:layout_constraintTop_toBottomOf="@+id/tvInvitedBy" />
 
 
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/ivCircle"
+        app:layout_constraintTop_toBottomOf="@+id/tvInvitedBy" />
+
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_invited_gallery.xml b/core/src/main/res/layout/list_item_invited_gallery.xml
index 93c89ce3a0046ecf005fd79743eec174d75f6c5a..63c32784397f4ea9009474402ad55a722269287f 100644
--- a/core/src/main/res/layout/list_item_invited_gallery.xml
+++ b/core/src/main/res/layout/list_item_invited_gallery.xml
@@ -90,4 +90,16 @@
         app:layout_constraintStart_toEndOf="@id/btnAccept"
         app:layout_constraintTop_toBottomOf="@+id/tvInviterName" />
 
+
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/ivGallery"
+        app:layout_constraintTop_toBottomOf="@+id/tvInviterName" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_invited_group.xml b/core/src/main/res/layout/list_item_invited_group.xml
index 4cf4a5d99b522967aee185910a1006ab7e5d940e..2ad031dfa3a02e5b575fc72fdbc17757d285d7ea 100644
--- a/core/src/main/res/layout/list_item_invited_group.xml
+++ b/core/src/main/res/layout/list_item_invited_group.xml
@@ -101,4 +101,17 @@
         app:layout_constraintStart_toEndOf="@id/btnAccept"
         app:layout_constraintTop_toBottomOf="@+id/tvInviterName" />
 
+
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/ivGroup"
+        app:layout_constraintTop_toBottomOf="@+id/tvInviterName" />
+
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_knock_request.xml b/core/src/main/res/layout/list_item_knock_request.xml
index 60906170fa64e93c211a73cb0ca0ab50f4a8230b..685b91148226d023f7f6311ba03e36b64351f3fa 100644
--- a/core/src/main/res/layout/list_item_knock_request.xml
+++ b/core/src/main/res/layout/list_item_knock_request.xml
@@ -61,4 +61,15 @@ MessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessage"
         app:layout_constraintTop_toTopOf="@id/btnInvite" />
 
 
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tvReason" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_people_request.xml b/core/src/main/res/layout/list_item_people_request.xml
index 7315a0483d7eb54de5ca420b9fbab1f1ec389c92..d8f60007d63d042776c7ecc13c35b16042c7d83c 100644
--- a/core/src/main/res/layout/list_item_people_request.xml
+++ b/core/src/main/res/layout/list_item_people_request.xml
@@ -93,4 +93,18 @@
         app:layout_constraintStart_toEndOf="@id/btnAccept"
         app:layout_constraintTop_toTopOf="@id/btnAccept" />
 
+
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginTop="4dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/ivUserImage"
+        app:layout_constraintTop_toBottomOf="@+id/tvReasonMessage" />
+
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/layout/list_item_users_timeline.xml b/core/src/main/res/layout/list_item_users_timeline.xml
index 89466acb71cfbb2848ea025fb5e6f469d4965567..13107bf01eaaf0673875e28d5119c2de409526db 100644
--- a/core/src/main/res/layout/list_item_users_timeline.xml
+++ b/core/src/main/res/layout/list_item_users_timeline.xml
@@ -62,4 +62,14 @@
         app:layout_constraintTop_toTopOf="parent"
         tools:visibility="visible" />
 
+    <ProgressBar
+        android:id="@+id/vLoading"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="16dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index f5bbf55662b7636bf3e80ac98b8e0588c2245700..5e2533502b4666a0600a314841f16a9cf22f5042 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -135,9 +135,6 @@
     <string name="public_circle_explanation">Other users can ask to join</string>
     <string name="private_type">Private</string>
     <string name="private_circle_explanation">Accessible only by invitation</string>
-    <string name="gallery_name">Gallery name</string>
-    <string name="group_name">Group name</string>
-    <string name="group_topic">Group topic</string>
     <string name="remove_from_this_circle_but_do_not_unfollow">Remove from this circle, but do not unfollow</string>
     <string name="unfollow_completely_remove_from_all_circles">Unfollow completely (remove from all circles)</string>
     <string name="no_internet_connection">No Internet connection</string>
diff --git a/gallery/build.gradle b/gallery/build.gradle
index ed82e73faf148dde02c6d7741ae58f1c2ca04b4a..86b33be244657597c9e168f035d345bc62e7d6c1 100644
--- a/gallery/build.gradle
+++ b/gallery/build.gradle
@@ -54,14 +54,14 @@ dependencies {
     implementation 'com.jsibbold:zoomage:1.3.1'
 
     //ExoPlayer
-    def exoplayer_version = '1.2.1'
+    def exoplayer_version = '1.3.0'
     implementation "androidx.media3:media3-exoplayer:$exoplayer_version"
     implementation "androidx.media3:media3-ui:$exoplayer_version"
 
     //Hilt
     implementation "com.google.dagger:hilt-android:$rootProject.ext.hilt_version"
     kapt "com.google.dagger:hilt-compiler:$rootProject.ext.hilt_version"
-    implementation "androidx.hilt:hilt-work:1.1.0"
+    implementation 'androidx.hilt:hilt-work:1.2.0'
 
     testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.5'