diff --git a/vector/build.gradle b/vector/build.gradle
index a9a3217042..bf98ab3d77 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -143,8 +143,10 @@ android {
         resValue "bool", "useLoginV2", "false"
 
         // NotificationSettingsV2 is disabled. To be released in conjunction with iOS/Web
-        resValue "bool", "useNotificationSettingsV1", "true"
-        resValue "bool", "useNotificationSettingsV2", "false"
+        def useNotificationSettingsV2 = false
+        buildConfigField "Boolean", "USE_NOTIFICATION_SETTINGS_V2", "${useNotificationSettingsV2}"
+        resValue "bool", "useNotificationSettingsV1", "${!useNotificationSettingsV2}"
+        resValue "bool", "useNotificationSettingsV2", "${useNotificationSettingsV2}"
 
         buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping"
 
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 cce0c2a66f..6b42f1e428 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
@@ -106,6 +106,7 @@ import im.vector.app.features.roomprofile.RoomProfileFragment
 import im.vector.app.features.roomprofile.alias.RoomAliasFragment
 import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
 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
@@ -717,6 +718,11 @@ interface FragmentModule {
     @FragmentKey(RoomBannedMemberListFragment::class)
     fun bindRoomBannedMemberListFragment(fragment: RoomBannedMemberListFragment): Fragment
 
+    @Binds
+    @IntoMap
+    @FragmentKey(RoomNotificationSettingsFragment::class)
+    fun bindRoomNotificationSettingsFragment(fragment: RoomNotificationSettingsFragment): Fragment
+
     @Binds
     @IntoMap
     @FragmentKey(SearchFragment::class)
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/NotificationSettingsFooterItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/NotificationSettingsFooterItem.kt
new file mode 100644
index 0000000000..4608f2b1ce
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/NotificationSettingsFooterItem.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.core.epoxy.profiles.notifications
+
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.ClickListener
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.core.extensions.setTextWithColoredPart
+
+@EpoxyModelClass(layout = R.layout.item_notifications_footer)
+abstract class NotificationSettingsFooterItem : VectorEpoxyModel<NotificationSettingsFooterItem.Holder>() {
+
+    @EpoxyAttribute
+    var encrypted: Boolean = false
+
+    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
+    var clickListener: ClickListener? = null
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        val accountSettingsString = holder.view.context.getString(R.string.room_settings_room_notifications_account_settings)
+        val manageNotificationsString = holder.view.context.getString(
+                R.string.room_settings_room_notifications_manage_notifications,
+                accountSettingsString
+        )
+        val manageNotificationsBuilder = StringBuilder(manageNotificationsString)
+        if (encrypted) {
+            val encryptionNotice = holder.view.context.getString(R.string.room_settings_room_notifications_encryption_notice)
+            manageNotificationsBuilder.appendLine().append(encryptionNotice)
+        }
+
+        holder.textView.setTextWithColoredPart(
+                manageNotificationsBuilder.toString(),
+                accountSettingsString,
+                underline = true
+        ) {
+            clickListener?.invoke(holder.textView)
+        }
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val textView by bind<TextView>(R.id.footerText)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/RadioButtonItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/RadioButtonItem.kt
new file mode 100644
index 0000000000..37d16ab6b1
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/RadioButtonItem.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.epoxy.profiles.notifications
+
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.core.content.ContextCompat
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.ClickListener
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.core.epoxy.onClick
+
+@EpoxyModelClass(layout = R.layout.item_radio)
+abstract class RadioButtonItem : VectorEpoxyModel<RadioButtonItem.Holder>() {
+
+    @EpoxyAttribute
+    var title: CharSequence? = null
+
+    @StringRes
+    @EpoxyAttribute
+    var titleRes: Int? = null
+
+    @EpoxyAttribute
+    var selected = false
+
+    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
+    lateinit var listener: ClickListener
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        holder.view.onClick(listener)
+        if (titleRes != null) {
+            holder.titleText.setText(titleRes!!)
+        } else {
+            holder.titleText.text = title
+        }
+
+        if (selected) {
+            holder.radioImage.setImageDrawable(ContextCompat.getDrawable(holder.view.context, R.drawable.ic_radio_on))
+            holder.radioImage.contentDescription = holder.view.context.getString(R.string.a11y_checked)
+        } else {
+            holder.radioImage.setImageDrawable(ContextCompat.getDrawable(holder.view.context, R.drawable.ic_radio_off))
+            holder.radioImage.contentDescription = holder.view.context.getString(R.string.a11y_unchecked)
+        }
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val titleText by bind<TextView>(R.id.actionTitle)
+        val radioImage by bind<ImageView>(R.id.radioIcon)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/TextHeaderItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/TextHeaderItem.kt
new file mode 100644
index 0000000000..2dfe7be2e6
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/epoxy/profiles/notifications/TextHeaderItem.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.epoxy.profiles.notifications
+
+import android.widget.TextView
+import androidx.annotation.StringRes
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+
+@EpoxyModelClass(layout = R.layout.item_text_header)
+abstract class TextHeaderItem : VectorEpoxyModel<TextHeaderItem.Holder>() {
+
+    @EpoxyAttribute
+    var text: String? = null
+
+    @StringRes
+    @EpoxyAttribute
+    var textRes: Int? = null
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        val textResource = textRes
+        if (textResource != null) {
+            holder.textView.setText(textResource)
+        } else {
+            holder.textView.text = text
+        }
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val textView by bind<TextView>(R.id.headerText)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/extensions/TextView.kt b/vector/src/main/java/im/vector/app/core/extensions/TextView.kt
index bb991ac32c..1c424f7071 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/TextView.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/TextView.kt
@@ -65,6 +65,23 @@ fun TextView.setTextWithColoredPart(@StringRes fullTextRes: Int,
     val coloredPart = resources.getString(coloredTextRes)
     // Insert colored part into the full text
     val fullText = resources.getString(fullTextRes, coloredPart)
+
+    setTextWithColoredPart(fullText, coloredPart, colorAttribute, underline, onClick)
+}
+
+/**
+ * Set text with a colored part
+ * @param fullText The full text.
+ * @param coloredPart The colored part of the text
+ * @param colorAttribute attribute of the color. Default to colorPrimary
+ * @param underline true to also underline the text. Default to false
+ * @param onClick attributes to handle click on the colored part if needed
+ */
+fun TextView.setTextWithColoredPart(fullText: String,
+                                    coloredPart: String,
+                                    @AttrRes colorAttribute: Int = R.attr.colorPrimary,
+                                    underline: Boolean = false,
+                                    onClick: (() -> Unit)? = null) {
     val color = ThemeUtils.getColor(context, colorAttribute)
 
     val foregroundSpan = ForegroundColorSpan(color)
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 4a563b563a..9ae6d4c39f 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
@@ -143,6 +143,8 @@ class HomeActivity :
         }
     }
 
+    override fun getCoordinatorLayout() = views.coordinatorLayout
+
     override fun getBinding() = ActivityHomeBinding.inflate(layoutInflater)
 
     override fun injectWith(injector: ScreenComponent) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionViewState.kt
new file mode 100644
index 0000000000..d063e07ed7
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionViewState.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.home.room.list.actions
+
+import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsViewState
+
+data class RoomListQuickActionViewState(
+        val roomListActionsArgs: RoomListActionsArgs,
+        val notificationSettingsViewState: RoomNotificationSettingsViewState
+)
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 94f9aaf496..8c1bdc086f 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
@@ -22,15 +22,23 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.recyclerview.widget.RecyclerView
+import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+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
 import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
 import im.vector.app.databinding.BottomSheetGenericListBinding
 import im.vector.app.features.navigation.Navigator
+import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsAction
+import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsViewEvents
+import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsViewModel
 import kotlinx.parcelize.Parcelize
+import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
 import javax.inject.Inject
 
 @Parcelize
@@ -54,11 +62,13 @@ class RoomListQuickActionsBottomSheet :
 
     private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
     @Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
-    @Inject lateinit var roomListActionsViewModelFactory: RoomListQuickActionsViewModel.Factory
+    @Inject lateinit var roomNotificationSettingsViewModelFactory: RoomNotificationSettingsViewModel.Factory
     @Inject lateinit var roomListActionsEpoxyController: RoomListQuickActionsEpoxyController
     @Inject lateinit var navigator: Navigator
+    @Inject lateinit var errorFormatter: ErrorFormatter
 
-    private val viewModel: RoomListQuickActionsViewModel by fragmentViewModel(RoomListQuickActionsViewModel::class)
+    private val roomListActionsArgs: RoomListActionsArgs by args()
+    private val viewModel: RoomNotificationSettingsViewModel by fragmentViewModel(RoomNotificationSettingsViewModel::class)
 
     override val showExpanded = true
 
@@ -80,6 +90,12 @@ class RoomListQuickActionsBottomSheet :
                 disableItemAnimation = true
         )
         roomListActionsEpoxyController.listener = this
+
+        viewModel.observeViewEvents {
+            when (it) {
+                is RoomNotificationSettingsViewEvents.Failure -> displayErrorDialog(it.throwable)
+            }
+        }
     }
 
     override fun onDestroyView() {
@@ -89,7 +105,11 @@ class RoomListQuickActionsBottomSheet :
     }
 
     override fun invalidate() = withState(viewModel) {
-        roomListActionsEpoxyController.setData(it)
+        val roomListViewState = RoomListQuickActionViewState(
+                roomListActionsArgs,
+                it
+        )
+        roomListActionsEpoxyController.setData(roomListViewState)
         super.invalidate()
     }
 
@@ -103,6 +123,10 @@ class RoomListQuickActionsBottomSheet :
         }
     }
 
+    override fun didSelectRoomNotificationState(roomNotificationState: RoomNotificationState) {
+        viewModel.handle(RoomNotificationSettingsAction.SelectNotificationState(roomNotificationState))
+    }
+
     companion object {
         fun newInstance(roomId: String, mode: RoomListActionsArgs.Mode): RoomListQuickActionsBottomSheet {
             return RoomListQuickActionsBottomSheet().apply {
@@ -110,4 +134,12 @@ class RoomListQuickActionsBottomSheet :
             }
         }
     }
+
+    private fun displayErrorDialog(throwable: Throwable) {
+        MaterialAlertDialogBuilder(requireActivity())
+                .setTitle(R.string.dialog_title_error)
+                .setMessage(errorFormatter.toHumanReadable(throwable))
+                .setPositiveButton(R.string.ok, null)
+                .show()
+    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt
index 4604159338..7e39156b18 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt
@@ -15,13 +15,19 @@
  */
 package im.vector.app.features.home.room.list.actions
 
+import androidx.annotation.StringRes
 import com.airbnb.epoxy.TypedEpoxyController
+import im.vector.app.BuildConfig
+import im.vector.app.R
 import im.vector.app.core.epoxy.bottomSheetDividerItem
 import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem
 import im.vector.app.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem
+import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem
 import im.vector.app.core.resources.ColorProvider
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.home.AvatarRenderer
+import im.vector.app.features.roomprofile.notifications.notificationOptions
+import im.vector.app.features.roomprofile.notifications.notificationStateMapped
 import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
 import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
@@ -33,16 +39,19 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
         private val avatarRenderer: AvatarRenderer,
         private val colorProvider: ColorProvider,
         private val stringProvider: StringProvider
-) : TypedEpoxyController<RoomListQuickActionsState>() {
+) : TypedEpoxyController<RoomListQuickActionViewState>() {
 
     var listener: Listener? = null
 
-    override fun buildModels(state: RoomListQuickActionsState) {
-        val roomSummary = state.roomSummary() ?: return
+    override fun buildModels(state: RoomListQuickActionViewState) {
+        val notificationViewState = state.notificationSettingsViewState
+        val roomSummary = notificationViewState.roomSummary() ?: return
         val host = this
-        val showAll = state.mode == RoomListActionsArgs.Mode.FULL
+        val isV2 = BuildConfig.USE_NOTIFICATION_SETTINGS_V2
+        // V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications
+        val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2
 
-        if (showAll) {
+        if (showFull) {
             // Preview, favorite, settings
             bottomSheetRoomPreviewItem {
                 id("room_preview")
@@ -63,17 +72,38 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
             }
         }
 
-        val selectedRoomState = state.roomNotificationState()
-        RoomListQuickActionsSharedAction.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0, selectedRoomState)
-        RoomListQuickActionsSharedAction.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1, selectedRoomState)
-        RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState)
-        RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState)
+        if (isV2) {
+            notificationViewState.notificationOptions.forEach {  notificationState ->
+                val title = titleForNotificationState(notificationState)
+                radioButtonItem {
+                    id(notificationState.name)
+                    titleRes(title)
+                    selected(notificationViewState.notificationStateMapped() == notificationState)
+                    listener {
+                    host.listener?.didSelectRoomNotificationState(notificationState)
+                    }
+                }
+            }
+        } else {
+            val selectedRoomState = notificationViewState.notificationState()
+            RoomListQuickActionsSharedAction.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0, selectedRoomState)
+            RoomListQuickActionsSharedAction.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1, selectedRoomState)
+            RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState)
+            RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState)
+        }
 
-        if (showAll) {
-            RoomListQuickActionsSharedAction.Leave(roomSummary.roomId).toBottomSheetItem(5)
+        if (showFull) {
+            RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !isV2).toBottomSheetItem(5)
         }
     }
 
+    @StringRes
+    private fun titleForNotificationState(notificationState: RoomNotificationState): Int? = when (notificationState) {
+        RoomNotificationState.ALL_MESSAGES_NOISY -> R.string.room_settings_all_messages
+        RoomNotificationState.MENTIONS_ONLY      -> R.string.room_settings_mention_and_keyword_only
+        RoomNotificationState.MUTE               -> R.string.room_settings_none
+        else -> null
+    }
     private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) {
         val host = this@RoomListQuickActionsEpoxyController
         val selected = when (this) {
@@ -86,7 +116,11 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
         return bottomSheetActionItem {
             id("action_$index")
             selected(selected)
-            iconRes(iconResId)
+            if (iconResId != null) {
+                iconRes(iconResId)
+            } else {
+                showIcon(false)
+            }
             textRes(titleRes)
             destructive(this@toBottomSheetItem.destructive)
             listener { host.listener?.didSelectMenuAction(this@toBottomSheetItem) }
@@ -95,5 +129,6 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
 
     interface Listener {
         fun didSelectMenuAction(quickAction: RoomListQuickActionsSharedAction)
+        fun didSelectRoomNotificationState(roomNotificationState: RoomNotificationState)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt
index 075dca0c52..6f93599d02 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt
@@ -23,7 +23,7 @@ import im.vector.app.core.platform.VectorSharedAction
 
 sealed class RoomListQuickActionsSharedAction(
         @StringRes val titleRes: Int,
-        @DrawableRes val iconResId: Int,
+        @DrawableRes val iconResId: Int?,
         val destructive: Boolean = false)
     : VectorSharedAction {
 
@@ -60,9 +60,9 @@ sealed class RoomListQuickActionsSharedAction(
             R.string.room_list_quick_actions_favorite_add,
             R.drawable.ic_star_24dp)
 
-    data class Leave(val roomId: String) : RoomListQuickActionsSharedAction(
+    data class Leave(val roomId: String, val showIcon: Boolean = true) : RoomListQuickActionsSharedAction(
             R.string.room_list_quick_actions_leave,
-            R.drawable.ic_room_actions_leave,
+            if (showIcon) R.drawable.ic_room_actions_leave else null,
             true
     )
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsState.kt
deleted file mode 100644
index 2731620cec..0000000000
--- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsState.kt
+++ /dev/null
@@ -1,33 +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.actions
-
-import com.airbnb.mvrx.Async
-import com.airbnb.mvrx.MvRxState
-import com.airbnb.mvrx.Uninitialized
-import org.matrix.android.sdk.api.session.room.model.RoomSummary
-import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
-
-data class RoomListQuickActionsState(
-        val roomId: String,
-        val mode: RoomListActionsArgs.Mode,
-        val roomSummary: Async<RoomSummary> = Uninitialized,
-        val roomNotificationState: Async<RoomNotificationState> = Uninitialized
-) : MvRxState {
-
-    constructor(args: RoomListActionsArgs) : this(roomId = args.roomId, mode = args.mode)
-}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsViewModel.kt
deleted file mode 100644
index 75e9459d2c..0000000000
--- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsViewModel.kt
+++ /dev/null
@@ -1,78 +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.actions
-
-import com.airbnb.mvrx.FragmentViewModelContext
-import com.airbnb.mvrx.MvRxViewModelFactory
-import com.airbnb.mvrx.ViewModelContext
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedInject
-import dagger.assisted.AssistedFactory
-import im.vector.app.core.platform.EmptyAction
-import im.vector.app.core.platform.EmptyViewEvents
-import im.vector.app.core.platform.VectorViewModel
-import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.rx.rx
-import org.matrix.android.sdk.rx.unwrap
-
-class RoomListQuickActionsViewModel @AssistedInject constructor(@Assisted initialState: RoomListQuickActionsState,
-                                                                session: Session
-) : VectorViewModel<RoomListQuickActionsState, EmptyAction, EmptyViewEvents>(initialState) {
-
-    @AssistedFactory
-    interface Factory {
-        fun create(initialState: RoomListQuickActionsState): RoomListQuickActionsViewModel
-    }
-
-    companion object : MvRxViewModelFactory<RoomListQuickActionsViewModel, RoomListQuickActionsState> {
-
-        @JvmStatic
-        override fun create(viewModelContext: ViewModelContext, state: RoomListQuickActionsState): RoomListQuickActionsViewModel? {
-            val fragment: RoomListQuickActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
-            return fragment.roomListActionsViewModelFactory.create(state)
-        }
-    }
-
-    private val room = session.getRoom(initialState.roomId)!!
-
-    init {
-        observeRoomSummary()
-        observeNotificationState()
-    }
-
-    private fun observeNotificationState() {
-        room
-                .rx()
-                .liveNotificationState()
-                .execute {
-                    copy(roomNotificationState = it)
-                }
-    }
-
-    private fun observeRoomSummary() {
-        room
-                .rx()
-                .liveRoomSummary()
-                .unwrap()
-                .execute {
-                    copy(roomSummary = it)
-                }
-    }
-
-    override fun handle(action: EmptyAction) {
-        // No op
-    }
-}
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 07ba442621..d28878283f 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
@@ -39,6 +39,7 @@ import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
 import im.vector.app.features.roomprofile.members.RoomMemberListFragment
 import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
 import im.vector.app.features.roomprofile.alias.RoomAliasFragment
+import im.vector.app.features.roomprofile.notifications.RoomNotificationSettingsFragment
 import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
 import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
 import javax.inject.Inject
@@ -107,12 +108,13 @@ class RoomProfileActivity :
                 .observe()
                 .subscribe { sharedAction ->
                     when (sharedAction) {
-                        RoomProfileSharedAction.OpenRoomMembers             -> openRoomMembers()
-                        RoomProfileSharedAction.OpenRoomSettings            -> openRoomSettings()
-                        RoomProfileSharedAction.OpenRoomAliasesSettings     -> openRoomAlias()
-                        RoomProfileSharedAction.OpenRoomPermissionsSettings -> openRoomPermissions()
-                        RoomProfileSharedAction.OpenRoomUploads             -> openRoomUploads()
-                        RoomProfileSharedAction.OpenBannedRoomMembers       -> openBannedRoomMembers()
+                        RoomProfileSharedAction.OpenRoomMembers                 -> openRoomMembers()
+                        RoomProfileSharedAction.OpenRoomSettings                -> openRoomSettings()
+                        RoomProfileSharedAction.OpenRoomAliasesSettings         -> openRoomAlias()
+                        RoomProfileSharedAction.OpenRoomPermissionsSettings     -> openRoomPermissions()
+                        RoomProfileSharedAction.OpenRoomUploads                 -> openRoomUploads()
+                        RoomProfileSharedAction.OpenBannedRoomMembers        -> openBannedRoomMembers()
+                        RoomProfileSharedAction.OpenRoomNotificationSettings -> openRoomNotificationSettings()
                     }.exhaustive
                 }
                 .disposeOnDestroy()
@@ -162,6 +164,10 @@ class RoomProfileActivity :
         addFragmentToBackstack(R.id.simpleFragmentContainer, RoomBannedMemberListFragment::class.java, roomProfileArgs)
     }
 
+    private fun openRoomNotificationSettings() {
+        addFragmentToBackstack(R.id.simpleFragmentContainer, RoomNotificationSettingsFragment::class.java, roomProfileArgs)
+    }
+
     override fun configure(toolbar: MaterialToolbar) {
         configureToolbar(toolbar)
     }
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 14ddf896ca..4b37d038b5 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
@@ -30,6 +30,7 @@ import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import com.airbnb.mvrx.withState
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import im.vector.app.BuildConfig
 import im.vector.app.R
 import im.vector.app.core.animations.AppBarStateChangeListener
 import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
@@ -253,9 +254,13 @@ class RoomProfileFragment @Inject constructor(
     }
 
     override fun onNotificationsClicked() {
-        RoomListQuickActionsBottomSheet
-                .newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
-                .show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
+        if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) {
+            roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings)
+        } else {
+            RoomListQuickActionsBottomSheet
+                    .newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
+                    .show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
+        }
     }
 
     override fun onUploadsClicked() {
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt
index 2a5775d1af..eb4ab56634 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileSharedAction.kt
@@ -28,4 +28,5 @@ sealed class RoomProfileSharedAction : VectorSharedAction {
     object OpenRoomUploads : RoomProfileSharedAction()
     object OpenRoomMembers : RoomProfileSharedAction()
     object OpenBannedRoomMembers : RoomProfileSharedAction()
+    object OpenRoomNotificationSettings : RoomProfileSharedAction()
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsAction.kt
new file mode 100644
index 0000000000..10c8861183
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsAction.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.roomprofile.notifications
+
+import im.vector.app.core.platform.VectorViewModelAction
+import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
+
+sealed class RoomNotificationSettingsAction : VectorViewModelAction {
+    data class SelectNotificationState(val notificationState: RoomNotificationState): RoomNotificationSettingsAction()
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsController.kt
new file mode 100644
index 0000000000..9a2085a7e8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsController.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.roomprofile.notifications
+
+import androidx.annotation.StringRes
+import com.airbnb.epoxy.TypedEpoxyController
+import im.vector.app.R
+import im.vector.app.core.epoxy.profiles.notifications.notificationSettingsFooterItem
+import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem
+import im.vector.app.core.epoxy.profiles.notifications.textHeaderItem
+import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
+import javax.inject.Inject
+
+class RoomNotificationSettingsController @Inject constructor() : TypedEpoxyController<RoomNotificationSettingsViewState>() {
+
+    interface Callback {
+        fun didSelectRoomNotificationState(roomNotificationState: RoomNotificationState)
+        fun didSelectAccountSettingsLink()
+    }
+
+    var callback: Callback? = null
+
+    init {
+        setData(null)
+    }
+
+    override fun buildModels(data: RoomNotificationSettingsViewState?) {
+        val host = this
+        data ?: return
+
+        textHeaderItem {
+            id("roomNotificationSettingsHeader")
+            textRes(R.string.room_settings_room_notifications_notify_me)
+        }
+        data.notificationOptions.forEach {  notificationState ->
+            val title = titleForNotificationState(notificationState)
+            radioButtonItem {
+                id(notificationState.name)
+                titleRes(title)
+                selected(data.notificationStateMapped() == notificationState)
+                listener {
+                    host.callback?.didSelectRoomNotificationState(notificationState)
+                }
+            }
+        }
+        notificationSettingsFooterItem {
+            id("roomNotificationSettingsFooter")
+            encrypted(data.roomSummary()?.isEncrypted == true)
+            clickListener {
+                host.callback?.didSelectAccountSettingsLink()
+            }
+        }
+    }
+
+    @StringRes
+    private fun titleForNotificationState(notificationState: RoomNotificationState): Int? = when (notificationState) {
+        RoomNotificationState.ALL_MESSAGES_NOISY -> R.string.room_settings_all_messages
+        RoomNotificationState.MENTIONS_ONLY      -> R.string.room_settings_mention_and_keyword_only
+        RoomNotificationState.MUTE               -> R.string.room_settings_none
+        else -> null
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsFragment.kt
new file mode 100644
index 0000000000..ce0fde32c6
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsFragment.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.roomprofile.notifications
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.app.R
+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.FragmentRoomSettingGenericBinding
+import im.vector.app.features.home.AvatarRenderer
+import im.vector.app.features.settings.VectorSettingsActivity
+import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
+import org.matrix.android.sdk.api.util.toMatrixItem
+import javax.inject.Inject
+
+class RoomNotificationSettingsFragment @Inject constructor(
+        val viewModelFactory: RoomNotificationSettingsViewModel.Factory,
+        private val roomNotificationSettingsController: RoomNotificationSettingsController,
+        private val avatarRenderer: AvatarRenderer
+) : VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
+        RoomNotificationSettingsController.Callback {
+
+    private val viewModel: RoomNotificationSettingsViewModel by fragmentViewModel()
+
+    override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding {
+        return FragmentRoomSettingGenericBinding.inflate(inflater, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        setupToolbar(views.roomSettingsToolbar)
+        roomNotificationSettingsController.callback = this
+        views.roomSettingsRecyclerView.configureWith(roomNotificationSettingsController, hasFixedSize = true)
+        setupWaitingView()
+        observeViewEvents()
+    }
+
+    override fun onDestroyView() {
+        views.roomSettingsRecyclerView.cleanup()
+        roomNotificationSettingsController.callback = null
+        super.onDestroyView()
+    }
+
+    private fun setupWaitingView() {
+        views.waitingView.waitingStatusText.setText(R.string.please_wait)
+        views.waitingView.waitingStatusText.isVisible = true
+    }
+
+    private fun observeViewEvents() {
+        viewModel.observeViewEvents {
+            when (it) {
+                is RoomNotificationSettingsViewEvents.Failure -> displayErrorDialog(it.throwable)
+            }
+        }
+    }
+
+    override fun invalidate() = withState(viewModel) { viewState ->
+        roomNotificationSettingsController.setData(viewState)
+        views.waitingView.root.isVisible = viewState.isLoading
+        renderRoomSummary(viewState)
+    }
+
+    override fun didSelectRoomNotificationState(roomNotificationState: RoomNotificationState) {
+        viewModel.handle(RoomNotificationSettingsAction.SelectNotificationState(roomNotificationState))
+    }
+
+    override fun didSelectAccountSettingsLink() {
+        navigator.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
+    }
+
+    private fun renderRoomSummary(state: RoomNotificationSettingsViewState) {
+        state.roomSummary()?.let {
+            views.roomSettingsToolbarTitleView.text = it.displayName
+            avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView)
+            views.roomSettingsDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel)
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewEvents.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewEvents.kt
new file mode 100644
index 0000000000..dda858283b
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewEvents.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.roomprofile.notifications
+
+import im.vector.app.core.platform.VectorViewEvents
+
+sealed class RoomNotificationSettingsViewEvents : VectorViewEvents {
+    data class Failure(val throwable: Throwable) : RoomNotificationSettingsViewEvents()
+}
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
new file mode 100644
index 0000000000..dd0535f51b
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.roomprofile.notifications
+
+import androidx.lifecycle.viewModelScope
+import com.airbnb.mvrx.FragmentViewModelContext
+import com.airbnb.mvrx.MvRxViewModelFactory
+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.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.rx.rx
+import org.matrix.android.sdk.rx.unwrap
+
+class RoomNotificationSettingsViewModel @AssistedInject constructor(
+        @Assisted initialState: RoomNotificationSettingsViewState,
+        session: Session
+) : VectorViewModel<RoomNotificationSettingsViewState, RoomNotificationSettingsAction, RoomNotificationSettingsViewEvents>(initialState) {
+
+    @AssistedFactory
+    interface Factory {
+        fun create(initialState: RoomNotificationSettingsViewState): RoomNotificationSettingsViewModel
+    }
+
+    companion object : MvRxViewModelFactory<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)
+            }
+        }
+    }
+
+    private val room = session.getRoom(initialState.roomId)!!
+
+    init {
+        observeSummary()
+        observeNotificationState()
+    }
+
+    private fun observeSummary() {
+        room.rx().liveRoomSummary()
+                .unwrap()
+                .execute { async ->
+                    copy(roomSummary = async)
+                }
+    }
+
+    private fun observeNotificationState() {
+        room.rx()
+                .liveNotificationState()
+                .execute {
+                    copy(notificationState = it)
+                }
+    }
+
+    override fun handle(action: RoomNotificationSettingsAction) {
+        when (action) {
+            is RoomNotificationSettingsAction.SelectNotificationState -> handleSelectNotificationState(action)
+        }
+    }
+
+    private fun handleSelectNotificationState(action: RoomNotificationSettingsAction.SelectNotificationState) {
+        setState { copy(isLoading = true) }
+        viewModelScope.launch {
+            runCatching {  room.setRoomNotificationState(action.notificationState) }
+                    .fold(
+                            {
+                                setState {
+                                    copy(isLoading = false, notificationState = Success(action.notificationState))
+                                }
+                            },
+                            {
+                                setState {
+                                    copy(isLoading = false)
+                                }
+                                _viewEvents.post(RoomNotificationSettingsViewEvents.Failure(it))
+                            }
+                    )
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.kt
new file mode 100644
index 0000000000..72e61fba70
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.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.features.roomprofile.notifications
+
+import com.airbnb.mvrx.Async
+import com.airbnb.mvrx.MvRxState
+import com.airbnb.mvrx.Success
+import com.airbnb.mvrx.Uninitialized
+import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
+import im.vector.app.features.roomprofile.RoomProfileArgs
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
+
+data class RoomNotificationSettingsViewState(
+        val roomId: String,
+        val roomSummary: Async<RoomSummary> = Uninitialized,
+        val isLoading: Boolean = false,
+        val notificationState: Async<RoomNotificationState> = Uninitialized
+)  : MvRxState {
+    constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
+    constructor(args: RoomListActionsArgs) : this(roomId = args.roomId)
+}
+
+/**
+ * Used to map this old room notification settings to the new options in v2.
+ */
+val RoomNotificationSettingsViewState.notificationStateMapped: Async<RoomNotificationState>
+    get() {
+        if ((roomSummary()?.isEncrypted == true && notificationState() == RoomNotificationState.MENTIONS_ONLY)
+                || notificationState() == RoomNotificationState.ALL_MESSAGES) {
+            /** if in an encrypted room, mentions notifications are not supported so show "All Messages" as selected.
+             * Also in the new settings there is no notion of notifications without sound so it maps to noisy also
+             */
+            return Success(RoomNotificationState.ALL_MESSAGES_NOISY)
+        }
+        return  notificationState
+    }
+/**
+ * Used to enumerate the new settings in notification settings v2. Notifications without sound and mentions in encrypted rooms not supported.
+ */
+val RoomNotificationSettingsViewState.notificationOptions: List<RoomNotificationState>
+    get() {
+        return if (roomSummary()?.isEncrypted == true) {
+            listOf(RoomNotificationState.ALL_MESSAGES_NOISY, RoomNotificationState.MUTE)
+        } else {
+            listOf(RoomNotificationState.ALL_MESSAGES_NOISY, RoomNotificationState.MENTIONS_ONLY, RoomNotificationState.MUTE)
+        }
+    }
diff --git a/vector/src/main/res/layout/item_notifications_footer.xml b/vector/src/main/res/layout/item_notifications_footer.xml
new file mode 100644
index 0000000000..36db166e8f
--- /dev/null
+++ b/vector/src/main/res/layout/item_notifications_footer.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    style="@style/Widget.Vector.TextView.Body"
+    android:id="@+id/footerText"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/layout_horizontal_margin"
+    android:paddingTop="@dimen/layout_vertical_margin"
+    android:paddingEnd="@dimen/layout_horizontal_margin"
+    android:paddingBottom="@dimen/layout_vertical_margin"
+    android:textColor="?vctr_content_secondary"
+    tools:text="@string/room_settings_room_notifications_encryption_notice" />
diff --git a/vector/src/main/res/layout/item_radio.xml b/vector/src/main/res/layout/item_radio.xml
new file mode 100644
index 0000000000..4cd5312dc0
--- /dev/null
+++ b/vector/src/main/res/layout/item_radio.xml
@@ -0,0 +1,40 @@
+<?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:clickable="true"
+    android:focusable="true"
+    android:minHeight="64dp"
+    android:foreground="?attr/selectableItemBackground"
+    android:paddingStart="@dimen/layout_horizontal_margin"
+    android:paddingEnd="@dimen/layout_horizontal_margin">
+
+    <TextView
+        android:id="@+id/actionTitle"
+        style="@style/Widget.Vector.TextView.Subtitle"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/layout_horizontal_margin"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:textColor="?vctr_content_primary"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/radioIcon"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="@string/room_settings_all_messages" />
+
+    <ImageView
+        android:id="@+id/radioIcon"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:contentDescription="@string/a11y_checked"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        tools:ignore="MissingPrefix"
+        tools:src="@drawable/ic_radio_on" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/vector/src/main/res/layout/item_text_header.xml b/vector/src/main/res/layout/item_text_header.xml
new file mode 100644
index 0000000000..3f876e5ece
--- /dev/null
+++ b/vector/src/main/res/layout/item_text_header.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/headerText"
+    style="@style/Widget.Vector.TextView.Subtitle"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/layout_horizontal_margin"
+    android:paddingTop="@dimen/layout_vertical_margin"
+    android:paddingEnd="@dimen/layout_horizontal_margin"
+    android:paddingBottom="@dimen/layout_vertical_margin"
+    android:textColor="?vctr_content_secondary"
+    android:textStyle="bold"
+    tools:text="@string/room_settings_room_notifications_notify_me" />
\ 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 acc4c1f9f1..46306b1888 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -1046,6 +1046,8 @@
     <string name="room_settings_all_messages">All messages</string>
     <string name="room_settings_mention_only">Mentions only</string>
     <string name="room_settings_mute">Mute</string>
+    <string name="room_settings_mention_and_keyword_only">Mentions &amp; Keywords only</string>
+    <string name="room_settings_none">None</string>
     <string name="room_settings_favourite">Favourite</string>
     <string name="room_settings_de_prioritize">De-prioritize</string>
     <string name="room_settings_direct_chat">Direct Chat</string>
@@ -1436,6 +1438,10 @@
     <string name="room_settings_category_access_visibility_title">Access and visibility</string>
     <string name="room_settings_directory_visibility">List this room in room directory</string>
     <string name="room_settings_room_notifications_title">Notifications</string>
+    <string name="room_settings_room_notifications_notify_me">Notify me for</string>
+    <string name="room_settings_room_notifications_encryption_notice">Please note that mentions &amp; keyword notifications are not available in encrypted rooms on mobile.</string>
+    <string name="room_settings_room_notifications_manage_notifications">You can manage notifications in %1$s.</string>
+    <string name="room_settings_room_notifications_account_settings">Account settings</string>
     <string name="room_settings_room_access_rules_pref_title">Room Access</string>
     <string name="room_settings_room_read_history_rules_pref_title">Room History Readability</string>
     <string name="room_settings_room_read_history_rules_pref_dialog_title">Who can read history?</string>