diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt
index d77dfcfe35..246813a524 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/thirdparty/model/ThirdPartyUser.kt
@@ -22,16 +22,16 @@ import org.matrix.android.sdk.api.util.JsonDict
 
 @JsonClass(generateAdapter = true)
 data class ThirdPartyUser(
-        /*
-            Required. A Matrix User ID represting a third party user.
+        /**
+         * Required. A Matrix User ID representing a third party user.
          */
         @Json(name = "userid") val userId: String,
-        /*
-            Required. The protocol ID that the third party location is a part of.
+        /**
+         * Required. The protocol ID that the third party location is a part of.
          */
         @Json(name = "protocol") val protocol: String,
-        /*
-            Required. Information used to identify this third party location.
+        /**
+         *  Required. Information used to identify this third party location.
          */
         @Json(name = "fields") val fields: JsonDict
 )
diff --git a/newsfragment/1458.feature b/newsfragment/1458.feature
new file mode 100644
index 0000000000..ded4f549ed
--- /dev/null
+++ b/newsfragment/1458.feature
@@ -0,0 +1 @@
+Allow user to add custom "network" in room search
\ No newline at end of file
diff --git a/newsfragment/3196.feature b/newsfragment/3196.feature
new file mode 100644
index 0000000000..ca84dd51c8
--- /dev/null
+++ b/newsfragment/3196.feature
@@ -0,0 +1 @@
+Add Gitter.im as a default in the Change Network menu
\ No newline at end of file
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt
index 55ec8b605e..de469b9e3a 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Activity.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Activity.kt
@@ -94,6 +94,10 @@ fun <T : Fragment> AppCompatActivity.addFragmentToBackstack(
     }
 }
 
+fun AppCompatActivity.popBackstack() {
+    supportFragmentManager.popBackStack()
+}
+
 fun AppCompatActivity.resetBackstack() {
     repeat(supportFragmentManager.backStackEntryCount) {
         supportFragmentManager.popBackStack()
diff --git a/vector/src/main/java/im/vector/app/core/ui/list/VerticalMarginItem.kt b/vector/src/main/java/im/vector/app/core/ui/list/VerticalMarginItem.kt
new file mode 100644
index 0000000000..ec99c7c215
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/ui/list/VerticalMarginItem.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 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.ui.list
+
+import android.view.View
+import androidx.core.view.updateLayoutParams
+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
+
+/**
+ * A generic item with empty space.
+ */
+@EpoxyModelClass(layout = R.layout.item_vertical_margin)
+abstract class VerticalMarginItem : VectorEpoxyModel<VerticalMarginItem.Holder>() {
+
+    @EpoxyAttribute
+    var heightInPx: Int = 0
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        holder.space.updateLayoutParams {
+            height = heightInPx
+        }
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val space by bind<View>(R.id.item_vertical_margin_space)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt b/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt
index b59b24fe55..47059128a1 100644
--- a/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt
+++ b/vector/src/main/java/im/vector/app/features/discovery/SettingsContinueCancelItem.kt
@@ -33,6 +33,9 @@ abstract class SettingsContinueCancelItem : EpoxyModelWithHolder<SettingsContinu
     @EpoxyAttribute
     var continueOnClick: ClickListener? = null
 
+    @EpoxyAttribute
+    var canContinue: Boolean = true
+
     @EpoxyAttribute
     var cancelOnClick: ClickListener? = null
 
@@ -43,6 +46,7 @@ abstract class SettingsContinueCancelItem : EpoxyModelWithHolder<SettingsContinu
 
         continueText?.let { holder.continueButton.text = it }
         holder.continueButton.onClick(continueOnClick)
+        holder.continueButton.isEnabled = canContinue
     }
 
     class Holder : VectorEpoxyHolder() {
diff --git a/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt b/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt
index f8bcbddd34..8e9b72d2d8 100644
--- a/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt
+++ b/vector/src/main/java/im/vector/app/features/form/FormEditTextItem.kt
@@ -19,6 +19,7 @@ package im.vector.app.features.form
 import android.text.Editable
 import android.view.View
 import android.view.inputmethod.EditorInfo
+import android.widget.TextView
 import androidx.core.view.isVisible
 import com.airbnb.epoxy.EpoxyAttribute
 import com.airbnb.epoxy.EpoxyModelClass
@@ -52,7 +53,7 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
     var inputType: Int? = null
 
     @EpoxyAttribute
-    var singleLine: Boolean? = null
+    var singleLine: Boolean = true
 
     @EpoxyAttribute
     var imeOptions: Int? = null
@@ -60,9 +61,13 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
     @EpoxyAttribute
     var endIconMode: Int? = null
 
-    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
+    // FIXME restore EpoxyAttribute.Option.DoNotHash and fix that properly
+    @EpoxyAttribute
     var onTextChange: ((String) -> Unit)? = null
 
+    @EpoxyAttribute
+    var editorActionListener: TextView.OnEditorActionListener? = null
+
     private val onTextChangeListener = object : SimpleTextWatcher() {
         override fun afterTextChanged(s: Editable) {
             onTextChange?.invoke(s.toString())
@@ -80,10 +85,11 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
 
         holder.textInputEditText.isEnabled = enabled
         inputType?.let { holder.textInputEditText.inputType = it }
-        holder.textInputEditText.isSingleLine = singleLine ?: false
+        holder.textInputEditText.isSingleLine = singleLine
         holder.textInputEditText.imeOptions = imeOptions ?: EditorInfo.IME_ACTION_NONE
 
         holder.textInputEditText.addTextChangedListener(onTextChangeListener)
+        holder.textInputEditText.setOnEditorActionListener(editorActionListener)
         holder.bottomSeparator.isVisible = showBottomSeparator
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
index 3abf01583c..ed57ccb04c 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
@@ -65,6 +65,7 @@ import im.vector.app.features.pin.PinActivity
 import im.vector.app.features.pin.PinArgs
 import im.vector.app.features.pin.PinMode
 import im.vector.app.features.roomdirectory.RoomDirectoryActivity
+import im.vector.app.features.roomdirectory.RoomDirectoryData
 import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
 import im.vector.app.features.roomdirectory.roompreview.RoomPreviewActivity
 import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
@@ -86,7 +87,6 @@ import im.vector.app.features.widgets.WidgetArgsBuilder
 import im.vector.app.space
 import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import org.matrix.android.sdk.api.session.terms.TermsService
 import org.matrix.android.sdk.api.session.widgets.model.Widget
 import org.matrix.android.sdk.api.session.widgets.model.WidgetType
@@ -129,7 +129,7 @@ class DefaultNavigator @Inject constructor(
         }
         appStateHandler.setCurrentSpace(spaceId)
         when (postSwitchSpaceAction) {
-            Navigator.PostSwitchSpaceAction.None -> {
+            Navigator.PostSwitchSpaceAction.None                 -> {
                 // go back to home if we are showing room details?
                 // This is a bit ugly, but the navigator is supposed to know about the activity stack
                 if (context is RoomDetailActivity) {
@@ -139,7 +139,7 @@ class DefaultNavigator @Inject constructor(
             Navigator.PostSwitchSpaceAction.OpenAddExistingRooms -> {
                 startActivity(context, SpaceManageActivity.newIntent(context, spaceId, ManageType.AddRooms), false)
             }
-            is Navigator.PostSwitchSpaceAction.OpenDefaultRoom -> {
+            is Navigator.PostSwitchSpaceAction.OpenDefaultRoom   -> {
                 val args = RoomDetailArgs(
                         postSwitchSpaceAction.roomId,
                         eventId = null,
@@ -278,7 +278,7 @@ class DefaultNavigator @Inject constructor(
                 val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
                 context.startActivity(intent)
             }
-            is RoomGroupingMethod.BySpace -> {
+            is RoomGroupingMethod.BySpace       -> {
                 val selectedSpace = groupingMethod.space()
                 if (selectedSpace == null) {
                     val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
@@ -320,7 +320,7 @@ class DefaultNavigator @Inject constructor(
                 val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
                 context.startActivity(intent)
             }
-            is RoomGroupingMethod.BySpace -> {
+            is RoomGroupingMethod.BySpace       -> {
                 if (currentGroupingMethod.spaceSummary != null) {
                     // let user decides if he does it from space or room
                     (context as? AppCompatActivity)?.supportFragmentManager?.let { fm ->
diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
index 444c48bddb..cf0263a1e8 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
@@ -26,11 +26,11 @@ import im.vector.app.features.crypto.recover.SetupMode
 import im.vector.app.features.login.LoginConfig
 import im.vector.app.features.media.AttachmentData
 import im.vector.app.features.pin.PinMode
+import im.vector.app.features.roomdirectory.RoomDirectoryData
 import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
 import im.vector.app.features.settings.VectorSettingsActivity
 import im.vector.app.features.share.SharedData
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import org.matrix.android.sdk.api.session.terms.TermsService
 import org.matrix.android.sdk.api.session.widgets.model.Widget
 import org.matrix.android.sdk.api.util.MatrixItem
@@ -44,7 +44,7 @@ interface Navigator {
     sealed class PostSwitchSpaceAction {
         object None : PostSwitchSpaceAction()
         data class OpenDefaultRoom(val roomId: String, val showShareSheet: Boolean) : PostSwitchSpaceAction()
-        object OpenAddExistingRooms: PostSwitchSpaceAction()
+        object OpenAddExistingRooms : PostSwitchSpaceAction()
     }
 
     fun switchToSpace(context: Context, spaceId: String, postSwitchSpaceAction: PostSwitchSpaceAction)
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt
index 16e5428b9c..fdab72caba 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt
@@ -21,7 +21,6 @@ import com.airbnb.mvrx.MvRxState
 import com.airbnb.mvrx.Uninitialized
 import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 
 data class PublicRoomsViewState(
         // The current filter
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt
index a94cb7709f..77eec57ab3 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt
@@ -17,7 +17,6 @@
 package im.vector.app.features.roomdirectory
 
 import im.vector.app.core.platform.VectorViewModelAction
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 
 sealed class RoomDirectoryAction : VectorViewModelAction {
     data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction()
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt
index d8edbcf503..9a63e81a2f 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt
@@ -25,6 +25,7 @@ import im.vector.app.R
 import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.extensions.addFragmentToBackstack
+import im.vector.app.core.extensions.popBackstack
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
 import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
@@ -58,7 +59,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>() {
                 .observe()
                 .subscribe { sharedAction ->
                     when (sharedAction) {
-                        is RoomDirectorySharedAction.Back           -> onBackPressed()
+                        is RoomDirectorySharedAction.Back           -> popBackstack()
                         is RoomDirectorySharedAction.CreateRoom     -> {
                             // Transmit the filter to the CreateRoomFragment
                             withState(roomDirectoryViewModel) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/RoomDirectoryData.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryData.kt
similarity index 75%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/RoomDirectoryData.kt
rename to vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryData.kt
index 91f429d773..49bb769460 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/RoomDirectoryData.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright (c) 2021 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.api.session.room.model.thirdparty
+package im.vector.app.features.roomdirectory
 
 /**
- * This class describes a rooms directory server.
+ * This class describes a rooms directory server protocol.
  */
 data class RoomDirectoryData(
-
         /**
          * The server name (might be null)
          * Set null when the server is the current user's home server.
@@ -30,7 +29,12 @@ data class RoomDirectoryData(
         /**
          * The display name (the server description)
          */
-        val displayName: String = DEFAULT_HOME_SERVER_NAME,
+        val displayName: String = MATRIX_PROTOCOL_NAME,
+
+        /**
+         * the avatar url
+         */
+        val avatarUrl: String? = null,
 
         /**
          * The third party server identifier
@@ -40,15 +44,10 @@ data class RoomDirectoryData(
         /**
          * Tell if all the federated servers must be included
          */
-        val includeAllNetworks: Boolean = false,
-
-        /**
-         * the avatar url
-         */
-        val avatarUrl: String? = null
+        val includeAllNetworks: Boolean = false
 ) {
 
     companion object {
-        const val DEFAULT_HOME_SERVER_NAME = "Matrix"
+        const val MATRIX_PROTOCOL_NAME = "Matrix"
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt
new file mode 100644
index 0000000000..0f29ae5986
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryServer.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.roomdirectory
+
+data class RoomDirectoryServer(
+        val serverName: String,
+
+        /**
+         * True if this is the current user server
+         */
+        val isUserServer: Boolean,
+
+        /**
+         * True if manually added, so it can be removed by the user
+         */
+        val isManuallyAdded: Boolean,
+
+        /**
+         * Supported protocols
+         * TODO Rename RoomDirectoryData to RoomDirectoryProtocols
+         */
+        val protocols: List<RoomDirectoryData>
+)
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt
index f64105b759..dc1cbfc58d 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt
@@ -37,7 +37,6 @@ import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import org.matrix.android.sdk.rx.rx
 import timber.log.Timber
@@ -230,9 +229,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
             Timber.w("Try to join an already joining room. Should not happen")
             return@withState
         }
-        val viaServers = state.roomDirectoryData.homeServer
-                ?.let { listOf(it) }
-                .orEmpty()
+        val viaServers = listOfNotNull(state.roomDirectoryData.homeServer)
         viewModelScope.launch {
             try {
                 session.joinRoom(action.roomId, viaServers = viaServers)
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomController.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomController.kt
index efb54650b8..aaf82c5791 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomController.kt
@@ -75,6 +75,7 @@ class CreateRoomController @Inject constructor(
             id("topic")
             enabled(enableFormElement)
             value(viewState.roomTopic)
+            singleLine(false)
             hint(host.stringProvider.getString(R.string.create_room_topic_hint))
 
             onTextChange { text ->
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt
index 7b2e329b6a..7cf8e538ac 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryItem.kt
@@ -16,10 +16,12 @@
 
 package im.vector.app.features.roomdirectory.picker
 
+import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.TextView
 import androidx.core.view.isInvisible
+import androidx.core.view.isVisible
 import com.airbnb.epoxy.EpoxyAttribute
 import com.airbnb.epoxy.EpoxyModelClass
 import im.vector.app.R
@@ -43,6 +45,9 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
     @EpoxyAttribute
     var includeAllNetworks: Boolean = false
 
+    @EpoxyAttribute
+    var checked: Boolean = false
+
     @EpoxyAttribute
     var globalListener: (() -> Unit)? = null
 
@@ -63,6 +68,7 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
 
         holder.nameView.text = directoryName
         holder.descriptionView.setTextOrHide(directoryDescription)
+        holder.checkedView.isVisible = checked
     }
 
     class Holder : VectorEpoxyHolder() {
@@ -71,5 +77,6 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
         val avatarView by bind<ImageView>(R.id.itemRoomDirectoryAvatar)
         val nameView by bind<TextView>(R.id.itemRoomDirectoryName)
         val descriptionView by bind<TextView>(R.id.itemRoomDirectoryDescription)
+        val checkedView by bind<View>(R.id.itemRoomDirectoryChecked)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt
index d51ad5040b..65d8f2d1cb 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryListCreator.kt
@@ -18,55 +18,110 @@ package im.vector.app.features.roomdirectory.picker
 
 import im.vector.app.R
 import im.vector.app.core.resources.StringArrayProvider
+import im.vector.app.features.roomdirectory.RoomDirectoryData
+import im.vector.app.features.roomdirectory.RoomDirectoryServer
 import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
 import javax.inject.Inject
 
-class RoomDirectoryListCreator @Inject constructor(private val stringArrayProvider: StringArrayProvider,
-                                                   private val session: Session) {
+class RoomDirectoryListCreator @Inject constructor(
+        private val stringArrayProvider: StringArrayProvider,
+        private val session: Session
+) {
 
-    fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>): List<RoomDirectoryData> {
-        val result = ArrayList<RoomDirectoryData>()
+    fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>,
+                           customHomeservers: Set<String>): List<RoomDirectoryServer> {
+        val result = ArrayList<RoomDirectoryServer>()
+
+        val protocols = ArrayList<RoomDirectoryData>()
 
         // Add user homeserver name
         val userHsName = session.myUserId.substringAfter(":")
 
-        result.add(RoomDirectoryData(
-                displayName = userHsName,
-                includeAllNetworks = true
-        ))
-
-        // Add user's HS but for Matrix public rooms only
-        result.add(RoomDirectoryData())
-
-        // Add custom directory servers
-        val hsNamesList = stringArrayProvider.getStringArray(R.array.room_directory_servers)
-        hsNamesList.forEach {
-            if (it != userHsName) {
-                // Use the server name as a default display name
-                result.add(RoomDirectoryData(
-                        homeServer = it,
-                        displayName = it,
-                        includeAllNetworks = true
-                ))
-            }
-        }
+        // Add default protocol
+        protocols.add(
+                RoomDirectoryData(
+                        homeServer = null,
+                        displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
+                        includeAllNetworks = false
+                )
+        )
 
         // Add result of the request
         thirdPartyProtocolData.forEach {
             it.value.instances?.forEach { thirdPartyProtocolInstance ->
-                result.add(RoomDirectoryData(
-                        homeServer = null,
-                        displayName = thirdPartyProtocolInstance.desc ?: "",
-                        thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId,
-                        includeAllNetworks = false,
-                        // Default to protocol icon
-                        avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon
-                ))
+                protocols.add(
+                        RoomDirectoryData(
+                                homeServer = null,
+                                displayName = thirdPartyProtocolInstance.desc ?: "",
+                                thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId,
+                                includeAllNetworks = false,
+                                // Default to protocol icon
+                                avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon
+                        )
+                )
             }
         }
 
+        // Add all rooms
+        protocols.add(
+                RoomDirectoryData(
+                        homeServer = null,
+                        displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
+                        includeAllNetworks = true
+                )
+        )
+
+        result.add(
+                RoomDirectoryServer(
+                        serverName = userHsName,
+                        isUserServer = true,
+                        isManuallyAdded = false,
+                        protocols = protocols
+                )
+        )
+
+        // Add custom directory servers, form the config file, excluding the current user homeserver
+        stringArrayProvider.getStringArray(R.array.room_directory_servers)
+                .filter { it != userHsName }
+                .forEach {
+                    // Use the server name as a default display name
+                    result.add(
+                            RoomDirectoryServer(
+                                    serverName = it,
+                                    isUserServer = false,
+                                    isManuallyAdded = false,
+                                    protocols = listOf(
+                                            RoomDirectoryData(
+                                                    homeServer = it,
+                                                    displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
+                                                    includeAllNetworks = false
+                                            )
+                                    )
+                            )
+                    )
+                }
+
+        // Add manually added server by the user
+        customHomeservers
+                .forEach {
+                    // Use the server name as a default display name
+                    result.add(
+                            RoomDirectoryServer(
+                                    serverName = it,
+                                    isUserServer = false,
+                                    isManuallyAdded = true,
+                                    protocols = listOf(
+                                            RoomDirectoryData(
+                                                    homeServer = it,
+                                                    displayName = RoomDirectoryData.MATRIX_PROTOCOL_NAME,
+                                                    includeAllNetworks = false
+                                            )
+                                    )
+                            )
+                    )
+                }
+
         return result
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt
index 36f2cd4296..8be3c6b2b2 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerAction.kt
@@ -17,7 +17,14 @@
 package im.vector.app.features.roomdirectory.picker
 
 import im.vector.app.core.platform.VectorViewModelAction
+import im.vector.app.features.roomdirectory.RoomDirectoryServer
 
 sealed class RoomDirectoryPickerAction : VectorViewModelAction {
     object Retry : RoomDirectoryPickerAction()
+    object EnterEditMode : RoomDirectoryPickerAction()
+    object ExitEditMode : RoomDirectoryPickerAction()
+    data class SetServerUrl(val url: String) : RoomDirectoryPickerAction()
+    data class RemoveServer(val roomDirectoryServer: RoomDirectoryServer) : RoomDirectoryPickerAction()
+
+    object Submit : RoomDirectoryPickerAction()
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt
index 75e9807bd0..9a397c586d 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerController.kt
@@ -16,37 +16,62 @@
 
 package im.vector.app.features.roomdirectory.picker
 
+import android.text.InputType
+import android.view.KeyEvent
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.widget.TextView
 import com.airbnb.epoxy.TypedEpoxyController
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Incomplete
+import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
+import com.airbnb.mvrx.Uninitialized
 import im.vector.app.R
+import im.vector.app.core.epoxy.dividerItem
 import im.vector.app.core.epoxy.errorWithRetryItem
 import im.vector.app.core.epoxy.loadingItem
 import im.vector.app.core.error.ErrorFormatter
+import im.vector.app.core.extensions.join
+import im.vector.app.core.resources.ColorProvider
 import im.vector.app.core.resources.StringProvider
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
+import im.vector.app.core.ui.list.genericButtonItem
+import im.vector.app.core.ui.list.verticalMarginItem
+import im.vector.app.core.utils.DimensionConverter
+import im.vector.app.features.discovery.settingsContinueCancelItem
+import im.vector.app.features.discovery.settingsInformationItem
+import im.vector.app.features.form.formEditTextItem
+import im.vector.app.features.roomdirectory.RoomDirectoryData
+import im.vector.app.features.roomdirectory.RoomDirectoryServer
+import org.matrix.android.sdk.api.failure.Failure
 import javax.inject.Inject
+import javax.net.ssl.HttpsURLConnection
 
-class RoomDirectoryPickerController @Inject constructor(private val stringProvider: StringProvider,
-                                                        private val errorFormatter: ErrorFormatter,
-                                                        private val roomDirectoryListCreator: RoomDirectoryListCreator
+class RoomDirectoryPickerController @Inject constructor(
+        private val stringProvider: StringProvider,
+        private val colorProvider: ColorProvider,
+        private val dimensionConverter: DimensionConverter,
+        private val errorFormatter: ErrorFormatter
 ) : TypedEpoxyController<RoomDirectoryPickerViewState>() {
 
+    var currentRoomDirectoryData: RoomDirectoryData? = null
     var callback: Callback? = null
 
-    var index = 0
+    private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
 
-    override fun buildModels(viewState: RoomDirectoryPickerViewState) {
+    override fun buildModels(data: RoomDirectoryPickerViewState) {
         val host = this
-        val asyncThirdPartyProtocol = viewState.asyncThirdPartyRequest
 
-        when (asyncThirdPartyProtocol) {
+        when (val asyncThirdPartyProtocol = data.asyncThirdPartyRequest) {
             is Success    -> {
-                val directories = roomDirectoryListCreator.computeDirectories(asyncThirdPartyProtocol())
-
-                directories.forEach {
-                    buildDirectory(it)
+                data.directories.join(
+                        each = { _, roomDirectoryServer -> buildDirectory(roomDirectoryServer) },
+                        between = { idx, _ -> buildDivider(idx) }
+                )
+                buildForm(data)
+                verticalMarginItem {
+                    id("space_bottom")
+                    heightInPx(host.dimensionConverter.dpToPx(16))
                 }
             }
             is Incomplete -> {
@@ -64,28 +89,131 @@ class RoomDirectoryPickerController @Inject constructor(private val stringProvid
         }
     }
 
-    private fun buildDirectory(roomDirectoryData: RoomDirectoryData) {
+    private fun buildForm(data: RoomDirectoryPickerViewState) {
+        buildDivider(1000)
         val host = this
-        roomDirectoryItem {
-            id(host.index++)
-
-            directoryName(roomDirectoryData.displayName)
-
-            val description = when {
-                roomDirectoryData.includeAllNetworks      ->
-                    host.stringProvider.getString(R.string.directory_server_all_rooms_on_server, roomDirectoryData.displayName)
-                "Matrix" == roomDirectoryData.displayName ->
-                    host.stringProvider.getString(R.string.directory_server_native_rooms, roomDirectoryData.displayName)
-                else                                      ->
-                    null
+        if (data.inEditMode) {
+            verticalMarginItem {
+                id("form_space")
+                heightInPx(host.dimensionConverter.dpToPx(16))
             }
+            settingsInformationItem {
+                id("form_notice")
+                message(host.stringProvider.getString(R.string.directory_add_a_new_server_prompt))
+                colorProvider(host.colorProvider)
+            }
+            verticalMarginItem {
+                id("form_space_2")
+                heightInPx(host.dimensionConverter.dpToPx(8))
+            }
+            formEditTextItem {
+                id("edit")
+                showBottomSeparator(false)
+                value(data.enteredServer)
+                imeOptions(EditorInfo.IME_ACTION_DONE)
+                editorActionListener(object : TextView.OnEditorActionListener {
+                    override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
+                        if (actionId == EditorInfo.IME_ACTION_DONE) {
+                            if (data.enteredServer.isNotEmpty()) {
+                                host.callback?.onSubmitServer()
+                            }
+                            return true
+                        }
+                        return false
+                    }
+                })
+                hint(host.stringProvider.getString(R.string.directory_server_placeholder))
+                inputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI)
+                onTextChange { text ->
+                    host.callback?.onEnterServerChange(text)
+                }
+                when (data.addServerAsync) {
+                    Uninitialized -> enabled(true)
+                    is Loading    -> enabled(false)
+                    is Success    -> enabled(false)
+                    is Fail       -> {
+                        enabled(true)
+                        errorMessage(host.getErrorMessage(data.addServerAsync.error))
+                    }
+                }
+            }
+            when (data.addServerAsync) {
+                Uninitialized,
+                is Fail    -> settingsContinueCancelItem {
+                    id("continueCancel")
+                    continueText(host.stringProvider.getString(R.string.ok))
+                    canContinue(data.enteredServer.isNotEmpty())
+                    continueOnClick { host.callback?.onSubmitServer() }
+                    cancelOnClick { host.callback?.onCancelEnterServer() }
+                }
+                is Loading -> loadingItem {
+                    id("addLoading")
+                }
+                is Success -> Unit /* This is a transitive state */
+            }
+        } else {
+            genericButtonItem {
+                id("add")
+                text(host.stringProvider.getString(R.string.directory_add_a_new_server))
+                textColor(host.colorProvider.getColor(R.color.riotx_accent))
+                buttonClickAction(View.OnClickListener {
+                    host.callback?.onStartEnterServer()
+                })
+            }
+        }
+    }
 
-            directoryDescription(description)
-            directoryAvatarUrl(roomDirectoryData.avatarUrl)
-            includeAllNetworks(roomDirectoryData.includeAllNetworks)
+    private fun getErrorMessage(error: Throwable): String {
+        return if (error is Failure.ServerError
+                && error.httpCode == HttpsURLConnection.HTTP_INTERNAL_ERROR /* 500 */) {
+            stringProvider.getString(R.string.directory_add_a_new_server_error)
+        } else {
+            errorFormatter.toHumanReadable(error)
+        }
+    }
 
-            globalListener {
-                host.callback?.onRoomDirectoryClicked(roomDirectoryData)
+    private fun buildDivider(idx: Int) {
+        val host = this
+        dividerItem {
+            id("divider_$idx")
+            color(host.dividerColor)
+        }
+    }
+
+    private fun buildDirectory(roomDirectoryServer: RoomDirectoryServer) {
+        val host = this
+        roomDirectoryServerItem {
+            id("server_$roomDirectoryServer")
+            serverName(roomDirectoryServer.serverName)
+            canRemove(roomDirectoryServer.isManuallyAdded)
+            removeListener { host.callback?.onRemoveServer(roomDirectoryServer) }
+
+            if (roomDirectoryServer.isUserServer) {
+                serverDescription(host.stringProvider.getString(R.string.directory_your_server))
+            }
+        }
+
+        roomDirectoryServer.protocols.forEach { roomDirectoryData ->
+            roomDirectoryItem {
+                id("server_${roomDirectoryServer}_proto_$roomDirectoryData")
+                directoryName(
+                        if (roomDirectoryData.includeAllNetworks) {
+                            host.stringProvider.getString(R.string.directory_server_all_rooms_on_server, roomDirectoryServer.serverName)
+                        } else {
+                            roomDirectoryData.displayName
+                        }
+                )
+                if (roomDirectoryData.displayName == RoomDirectoryData.MATRIX_PROTOCOL_NAME && !roomDirectoryData.includeAllNetworks) {
+                    directoryDescription(
+                            host.stringProvider.getString(R.string.directory_server_native_rooms, roomDirectoryServer.serverName)
+                    )
+                }
+                directoryAvatarUrl(roomDirectoryData.avatarUrl)
+                includeAllNetworks(roomDirectoryData.includeAllNetworks)
+                checked(roomDirectoryData == host.currentRoomDirectoryData)
+                globalListener {
+                    host.callback?.onRoomDirectoryClicked(roomDirectoryData)
+                }
             }
         }
     }
@@ -93,5 +221,10 @@ class RoomDirectoryPickerController @Inject constructor(private val stringProvid
     interface Callback {
         fun onRoomDirectoryClicked(roomDirectoryData: RoomDirectoryData)
         fun retry()
+        fun onStartEnterServer()
+        fun onEnterServerChange(server: String)
+        fun onSubmitServer()
+        fun onCancelEnterServer()
+        fun onRemoveServer(roomDirectoryServer: RoomDirectoryServer)
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt
index 7f205078f1..a32a3a897f 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt
@@ -18,7 +18,6 @@ package im.vector.app.features.roomdirectory.picker
 
 import android.os.Bundle
 import android.view.LayoutInflater
-import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
 import androidx.appcompat.app.AppCompatActivity
@@ -28,21 +27,22 @@ 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.OnBackPressed
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
 import im.vector.app.features.roomdirectory.RoomDirectoryAction
+import im.vector.app.features.roomdirectory.RoomDirectoryData
+import im.vector.app.features.roomdirectory.RoomDirectoryServer
 import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
 import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
 import im.vector.app.features.roomdirectory.RoomDirectoryViewModel
-
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import timber.log.Timber
 import javax.inject.Inject
 
-// TODO Menu to add custom room directory (not done in RiotWeb so far...)
 class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory,
                                                       private val roomDirectoryPickerController: RoomDirectoryPickerController
 ) : VectorBaseFragment<FragmentRoomDirectoryPickerBinding>(),
+        OnBackPressed,
         RoomDirectoryPickerController.Callback {
 
     private val viewModel: RoomDirectoryViewModel by activityViewModel()
@@ -65,6 +65,11 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
 
         sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
         setupRecyclerView()
+
+        // Give the current data to our controller. There maybe a better way to do that...
+        withState(viewModel) {
+            roomDirectoryPickerController.currentRoomDirectoryData = it.roomDirectoryData
+        }
     }
 
     override fun onDestroyView() {
@@ -73,18 +78,6 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
         super.onDestroyView()
     }
 
-    override fun getMenuRes() = R.menu.menu_directory_server_picker
-
-    override fun onOptionsItemSelected(item: MenuItem): Boolean {
-        if (item.itemId == R.id.action_add_custom_hs) {
-            // TODO
-            vectorBaseActivity.notImplemented("Entering custom homeserver")
-            return true
-        }
-
-        return super.onOptionsItemSelected(item)
-    }
-
     private fun setupRecyclerView() {
         views.roomDirectoryPickerList.configureWith(roomDirectoryPickerController)
         roomDirectoryPickerController.callback = this
@@ -97,6 +90,26 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
         sharedActionViewModel.post(RoomDirectorySharedAction.Back)
     }
 
+    override fun onStartEnterServer() {
+        pickerViewModel.handle(RoomDirectoryPickerAction.EnterEditMode)
+    }
+
+    override fun onCancelEnterServer() {
+        pickerViewModel.handle(RoomDirectoryPickerAction.ExitEditMode)
+    }
+
+    override fun onEnterServerChange(server: String) {
+        pickerViewModel.handle(RoomDirectoryPickerAction.SetServerUrl(server))
+    }
+
+    override fun onSubmitServer() {
+        pickerViewModel.handle(RoomDirectoryPickerAction.Submit)
+    }
+
+    override fun onRemoveServer(roomDirectoryServer: RoomDirectoryServer) {
+        pickerViewModel.handle(RoomDirectoryPickerAction.RemoveServer(roomDirectoryServer))
+    }
+
     override fun onResume() {
         super.onResume()
         (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.select_room_directory)
@@ -111,4 +124,16 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
         // Populate list with Epoxy
         roomDirectoryPickerController.setData(state)
     }
+
+    override fun onBackPressed(toolbarButton: Boolean): Boolean {
+        // Leave the add server mode if started
+        return withState(pickerViewModel) {
+            if (it.inEditMode) {
+                pickerViewModel.handle(RoomDirectoryPickerAction.ExitEditMode)
+                true
+            } else {
+                false
+            }
+        }
+    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt
index d85b7937a2..2558715834 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt
@@ -22,18 +22,28 @@ import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.MvRxViewModelFactory
 import com.airbnb.mvrx.Success
+import com.airbnb.mvrx.Uninitialized
 import com.airbnb.mvrx.ViewModelContext
 import dagger.assisted.Assisted
-import dagger.assisted.AssistedInject
 import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import im.vector.app.R
+import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.core.resources.StringProvider
+import im.vector.app.features.ui.UiStateRepository
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
 
-class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initialState: RoomDirectoryPickerViewState,
-                                                               private val session: Session)
-    : VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction, EmptyViewEvents>(initialState) {
+class RoomDirectoryPickerViewModel @AssistedInject constructor(
+        @Assisted initialState: RoomDirectoryPickerViewState,
+        private val session: Session,
+        private val uiStateRepository: UiStateRepository,
+        private val stringProvider: StringProvider,
+        private val roomDirectoryListCreator: RoomDirectoryListCreator
+) : VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction, EmptyViewEvents>(initialState) {
 
     @AssistedFactory
     interface Factory {
@@ -50,7 +60,22 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initial
     }
 
     init {
+        observeAndCompute()
         load()
+        loadCustomRoomDirectoryHomeservers()
+    }
+
+    private fun observeAndCompute() {
+        selectSubscribe(
+                RoomDirectoryPickerViewState::asyncThirdPartyRequest,
+                RoomDirectoryPickerViewState::customHomeservers
+        ) { async, custom ->
+            async()?.let {
+                setState {
+                    copy(directories = roomDirectoryListCreator.computeDirectories(it, custom))
+                }
+            }
+        }
     }
 
     private fun load() {
@@ -71,9 +96,101 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initial
         }
     }
 
+    private fun loadCustomRoomDirectoryHomeservers() {
+        setState {
+            copy(
+                    customHomeservers = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId)
+            )
+        }
+    }
+
     override fun handle(action: RoomDirectoryPickerAction) {
         when (action) {
-            RoomDirectoryPickerAction.Retry -> load()
+            RoomDirectoryPickerAction.Retry           -> load()
+            RoomDirectoryPickerAction.EnterEditMode   -> handleEnterEditMode()
+            RoomDirectoryPickerAction.ExitEditMode    -> handleExitEditMode()
+            is RoomDirectoryPickerAction.SetServerUrl -> handleSetServerUrl(action)
+            RoomDirectoryPickerAction.Submit          -> handleSubmit()
+            is RoomDirectoryPickerAction.RemoveServer -> handleRemoveServer(action)
+        }.exhaustive
+    }
+
+    private fun handleEnterEditMode() {
+        setState {
+            copy(
+                    inEditMode = true,
+                    enteredServer = "",
+                    addServerAsync = Uninitialized
+            )
+        }
+    }
+
+    private fun handleExitEditMode() {
+        setState {
+            copy(
+                    inEditMode = false,
+                    enteredServer = "",
+                    addServerAsync = Uninitialized
+            )
+        }
+    }
+
+    private fun handleSetServerUrl(action: RoomDirectoryPickerAction.SetServerUrl) {
+        setState {
+            copy(
+                    enteredServer = action.url
+            )
+        }
+    }
+
+    private fun handleSubmit() = withState { state ->
+        // First avoid duplicate
+        val enteredServer = state.enteredServer
+
+        val existingServerList = state.directories.map { it.serverName }
+
+        if (enteredServer in existingServerList) {
+            setState {
+                copy(addServerAsync = Fail(Throwable(stringProvider.getString(R.string.directory_add_a_new_server_error_already_added))))
+            }
+            return@withState
+        }
+
+        viewModelScope.launch {
+            setState {
+                copy(addServerAsync = Loading())
+            }
+            try {
+                session.getPublicRooms(
+                        server = enteredServer,
+                        publicRoomsParams = PublicRoomsParams(limit = 1)
+                )
+                // Success, let add the server to our local repository, and update the state
+                val newSet = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId) + enteredServer
+                uiStateRepository.setCustomRoomDirectoryHomeservers(session.sessionId, newSet)
+                setState {
+                    copy(
+                            inEditMode = false,
+                            enteredServer = "",
+                            addServerAsync = Uninitialized,
+                            customHomeservers = newSet
+                    )
+                }
+            } catch (failure: Throwable) {
+                setState {
+                    copy(addServerAsync = Fail(failure))
+                }
+            }
+        }
+    }
+
+    private fun handleRemoveServer(action: RoomDirectoryPickerAction.RemoveServer) {
+        val newSet = uiStateRepository.getCustomRoomDirectoryHomeservers(session.sessionId) - action.roomDirectoryServer.serverName
+        uiStateRepository.setCustomRoomDirectoryHomeservers(session.sessionId, newSet)
+        setState {
+            copy(
+                    customHomeservers = newSet
+            )
         }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt
index 61cf50e8dd..5cdee862ab 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt
@@ -19,8 +19,15 @@ package im.vector.app.features.roomdirectory.picker
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.MvRxState
 import com.airbnb.mvrx.Uninitialized
+import im.vector.app.features.roomdirectory.RoomDirectoryServer
 import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
 
 data class RoomDirectoryPickerViewState(
-        val asyncThirdPartyRequest: Async<Map<String, ThirdPartyProtocol>> = Uninitialized
+        val asyncThirdPartyRequest: Async<Map<String, ThirdPartyProtocol>> = Uninitialized,
+        val customHomeservers: Set<String> = emptySet(),
+        val inEditMode: Boolean = false,
+        val enteredServer: String = "",
+        val addServerAsync: Async<Unit> = Uninitialized,
+        // computed
+        val directories: List<RoomDirectoryServer> = emptyList()
 ) : MvRxState
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt
new file mode 100644
index 0000000000..6efb41d5b1
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryServerItem.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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.roomdirectory.picker
+
+import android.view.View
+import android.widget.TextView
+import androidx.core.view.isVisible
+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
+import im.vector.app.core.extensions.setTextOrHide
+
+@EpoxyModelClass(layout = R.layout.item_room_directory_server)
+abstract class RoomDirectoryServerItem : VectorEpoxyModel<RoomDirectoryServerItem.Holder>() {
+
+    @EpoxyAttribute
+    var serverName: String? = null
+
+    @EpoxyAttribute
+    var serverDescription: String? = null
+
+    @EpoxyAttribute
+    var canRemove: Boolean = false
+
+    @EpoxyAttribute
+    var removeListener: ClickListener? = null
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        holder.nameView.text = serverName
+        holder.descriptionView.setTextOrHide(serverDescription)
+        holder.deleteView.isVisible = canRemove
+        holder.deleteView.onClick(removeListener)
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val nameView by bind<TextView>(R.id.itemRoomDirectoryServerName)
+        val descriptionView by bind<TextView>(R.id.itemRoomDirectoryServerDescription)
+        val deleteView by bind<View>(R.id.itemRoomDirectoryServerRemove)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
index 445d02d6e2..f9cf8e6dd7 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
@@ -25,9 +25,9 @@ import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
 import im.vector.app.databinding.ActivitySimpleBinding
+import im.vector.app.features.roomdirectory.RoomDirectoryData
 import kotlinx.parcelize.Parcelize
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
-import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import org.matrix.android.sdk.api.util.MatrixItem
 import timber.log.Timber
 
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt
index 24836bc504..a07589d501 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt
@@ -102,6 +102,7 @@ class RoomSettingsController @Inject constructor(
             id("topic")
             enabled(data.actionPermissions.canChangeTopic)
             value(data.newTopic ?: roomSummary.topic)
+            singleLine(false)
             hint(host.stringProvider.getString(R.string.room_settings_topic_hint))
 
             onTextChange { text ->
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDefaultRoomEpoxyController.kt b/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDefaultRoomEpoxyController.kt
index a8b85c9887..3f712a4fda 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDefaultRoomEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDefaultRoomEpoxyController.kt
@@ -69,7 +69,6 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
             id("roomName1")
             enabled(true)
             value(firstRoomName)
-            singleLine(true)
             hint(host.stringProvider.getString(R.string.create_room_name_section))
             endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
             showBottomSeparator(false)
@@ -83,7 +82,6 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
             id("roomName2")
             enabled(true)
             value(secondRoomName)
-            singleLine(true)
             hint(host.stringProvider.getString(R.string.create_room_name_section))
             endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
             showBottomSeparator(false)
@@ -97,7 +95,6 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
             id("roomName3")
             enabled(true)
             value(thirdRoomName)
-            singleLine(true)
             hint(host.stringProvider.getString(R.string.create_room_name_section))
             endIconMode(TextInputLayout.END_ICON_CLEAR_TEXT)
             showBottomSeparator(false)
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDetailEpoxyController.kt b/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDetailEpoxyController.kt
index 6ab35d3bf6..662b272d40 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDetailEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/SpaceDetailEpoxyController.kt
@@ -64,7 +64,6 @@ class SpaceDetailEpoxyController @Inject constructor(
             enabled(true)
             value(data?.name)
             hint(host.stringProvider.getString(R.string.create_room_name_hint))
-            singleLine(true)
             showBottomSeparator(false)
             errorMessage(data?.nameInlineError)
 //            onBind { _, view, _ ->
diff --git a/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt b/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt
index 1ec3a8ab46..e46c3516ca 100644
--- a/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt
+++ b/vector/src/main/java/im/vector/app/features/ui/SharedPreferencesUiStateRepository.kt
@@ -39,7 +39,7 @@ class SharedPreferencesUiStateRepository @Inject constructor(
     override fun getDisplayMode(): RoomListDisplayMode {
         return when (sharedPreferences.getInt(KEY_DISPLAY_MODE, VALUE_DISPLAY_MODE_CATCHUP)) {
             VALUE_DISPLAY_MODE_PEOPLE -> RoomListDisplayMode.PEOPLE
-            VALUE_DISPLAY_MODE_ROOMS -> RoomListDisplayMode.ROOMS
+            VALUE_DISPLAY_MODE_ROOMS  -> RoomListDisplayMode.ROOMS
             else                      -> if (vectorPreferences.labAddNotificationTab()) {
                 RoomListDisplayMode.NOTIFICATIONS
             } else {
@@ -89,6 +89,18 @@ class SharedPreferencesUiStateRepository @Inject constructor(
         return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true)
     }
 
+    override fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set<String>) {
+        sharedPreferences.edit {
+            putStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", servers)
+        }
+    }
+
+    override fun getCustomRoomDirectoryHomeservers(sessionId: String): Set<String> {
+        return sharedPreferences.getStringSet("$KEY_CUSTOM_DIRECTORY_HOMESERVER@$sessionId", null)
+                .orEmpty()
+                .toSet()
+    }
+
     companion object {
         private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE"
         private const val VALUE_DISPLAY_MODE_CATCHUP = 0
@@ -98,5 +110,7 @@ class SharedPreferencesUiStateRepository @Inject constructor(
         private const val KEY_SELECTED_SPACE = "UI_STATE_SELECTED_SPACE"
         private const val KEY_SELECTED_GROUP = "UI_STATE_SELECTED_GROUP"
         private const val KEY_SELECTED_METHOD = "UI_STATE_SELECTED_METHOD"
+
+        private const val KEY_CUSTOM_DIRECTORY_HOMESERVER = "KEY_CUSTOM_DIRECTORY_HOMESERVER"
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt b/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt
index 935da83f5d..3c48f8972d 100644
--- a/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt
+++ b/vector/src/main/java/im/vector/app/features/ui/UiStateRepository.kt
@@ -32,6 +32,7 @@ interface UiStateRepository {
 
     fun storeDisplayMode(displayMode: RoomListDisplayMode)
 
+    // TODO Handle SharedPreference per session in a better way, also to cleanup when login out
     fun storeSelectedSpace(spaceId: String?, sessionId: String)
     fun storeSelectedGroup(groupId: String?, sessionId: String)
 
@@ -40,4 +41,7 @@ interface UiStateRepository {
     fun getSelectedSpace(sessionId: String): String?
     fun getSelectedGroup(sessionId: String): String?
     fun isGroupingMethodSpace(sessionId: String): Boolean
+
+    fun setCustomRoomDirectoryHomeservers(sessionId: String, servers: Set<String>)
+    fun getCustomRoomDirectoryHomeservers(sessionId: String): Set<String>
 }
diff --git a/vector/src/main/res/layout/item_room_directory.xml b/vector/src/main/res/layout/item_room_directory.xml
index 391f52ad92..19a457ec37 100644
--- a/vector/src/main/res/layout/item_room_directory.xml
+++ b/vector/src/main/res/layout/item_room_directory.xml
@@ -1,5 +1,4 @@
 <?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"
@@ -15,23 +14,23 @@
         android:id="@+id/itemRoomDirectoryAvatar"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginStart="8dp"
+        android:layout_marginStart="@dimen/layout_horizontal_margin"
         android:layout_marginTop="4dp"
         android:layout_marginBottom="4dp"
         android:background="@drawable/circle"
         android:contentDescription="@string/avatar"
         android:padding="8dp"
-        app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryBottomSeparator"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        tools:src="@tools:sample/avatars" />
+        tools:src="@drawable/network_matrix" />
 
     <TextView
         android:id="@+id/itemRoomDirectoryName"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
         android:ellipsize="end"
         android:lines="1"
         android:maxLines="2"
@@ -39,36 +38,46 @@
         android:textSize="15sp"
         android:textStyle="bold"
         app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryDescription"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/itemRoomDirectoryChecked"
         app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintVertical_chainStyle="packed"
+        app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
         tools:text="@tools:sample/lorem/random" />
 
     <TextView
         android:id="@+id/itemRoomDirectoryDescription"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginStart="16dp"
-        android:layout_marginEnd="16dp"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
         android:ellipsize="end"
         android:lines="1"
         android:maxLines="2"
         android:textColor="?riotx_text_primary"
-        android:textSize="15sp"
-        app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryBottomSeparator"
-        app:layout_constraintEnd_toEndOf="parent"
+        android:textSize="14sp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/itemRoomDirectoryChecked"
         app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
         app:layout_constraintTop_toBottomOf="@id/itemRoomDirectoryName"
-        tools:text="@string/directory_server_all_rooms_on_server" />
+        app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
+        tools:text="@string/directory_server_native_rooms"
+        tools:visibility="visible" />
 
-    <View
-        android:id="@+id/itemRoomDirectoryBottomSeparator"
-        android:layout_width="0dp"
-        android:layout_height="1dp"
-        android:background="?riotx_header_panel_border_mobile"
+    <ImageView
+        android:id="@+id/itemRoomDirectoryChecked"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/layout_horizontal_margin"
+        android:layout_marginEnd="@dimen/layout_horizontal_margin"
+        android:contentDescription="@string/avatar"
+        android:padding="8dp"
+        android:src="@drawable/ic_check_on"
+        android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
+        app:layout_constraintTop_toTopOf="parent"
+        tools:visibility="visible" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/vector/src/main/res/layout/item_room_directory_server.xml b/vector/src/main/res/layout/item_room_directory_server.xml
new file mode 100644
index 0000000000..5705e1c623
--- /dev/null
+++ b/vector/src/main/res/layout/item_room_directory_server.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?vctr_list_header_background_color"
+    android:minHeight="?listPreferredItemHeight">
+
+    <TextView
+        android:id="@+id/itemRoomDirectoryServerName"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/layout_horizontal_margin"
+        android:layout_marginEnd="8dp"
+        android:ellipsize="end"
+        android:lines="1"
+        android:maxLines="2"
+        android:textColor="?riotx_text_primary"
+        android:textSize="16sp"
+        android:textStyle="bold"
+        app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryServerDescription"
+        app:layout_constraintEnd_toStartOf="@id/itemRoomDirectoryServerRemove"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_chainStyle="packed"
+        app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
+        tools:text="@tools:sample/lorem/random" />
+
+    <TextView
+        android:id="@+id/itemRoomDirectoryServerDescription"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/layout_horizontal_margin"
+        android:layout_marginEnd="8dp"
+        android:ellipsize="end"
+        android:lines="1"
+        android:maxLines="2"
+        android:textColor="?riotx_text_secondary"
+        android:textSize="15sp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/itemRoomDirectoryServerRemove"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/itemRoomDirectoryServerName"
+        app:layout_goneMarginEnd="@dimen/layout_horizontal_margin"
+        tools:text="@string/directory_your_server"
+        tools:visibility="visible" />
+
+    <ImageView
+        android:id="@+id/itemRoomDirectoryServerRemove"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/layout_horizontal_margin"
+        android:layout_marginEnd="@dimen/layout_horizontal_margin"
+        android:contentDescription="@string/avatar"
+        android:padding="8dp"
+        android:src="@drawable/ic_delete"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:tint="@color/vector_error_color"
+        tools:ignore="MissingPrefix"
+        tools:visibility="visible" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/vector/src/main/res/layout/item_vertical_margin.xml b/vector/src/main/res/layout/item_vertical_margin.xml
new file mode 100644
index 0000000000..fac46e47ea
--- /dev/null
+++ b/vector/src/main/res/layout/item_vertical_margin.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Space xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/item_vertical_margin_space"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/layout_vertical_margin" />
diff --git a/vector/src/main/res/menu/menu_directory_server_picker.xml b/vector/src/main/res/menu/menu_directory_server_picker.xml
deleted file mode 100644
index c544c80f8c..0000000000
--- a/vector/src/main/res/menu/menu_directory_server_picker.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-
-    <item
-        android:id="@+id/action_add_custom_hs"
-        android:icon="@drawable/ic_add_black"
-        android:title="@string/action_open"
-        android:visible="@bool/false_not_implemented"
-        app:iconTint="?colorAccent"
-        app:showAsAction="always" />
-
-</menu>
\ No newline at end of file
diff --git a/vector/src/main/res/values/config.xml b/vector/src/main/res/values/config.xml
index 2b22b1c49b..30ca8d7f56 100755
--- a/vector/src/main/res/values/config.xml
+++ b/vector/src/main/res/values/config.xml
@@ -23,6 +23,7 @@
 
     <string-array name="room_directory_servers" translatable="false">
         <item>matrix.org</item>
+        <item>gitter.im</item>
     </string-array>
 
 </resources>
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 1e3d246e64..6b1f00287e 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -1584,9 +1584,14 @@
     <string name="select_room_directory">Select a room directory</string>
     <string name="directory_server_fail_to_retrieve_server">The server may be unavailable or overloaded</string>
     <string name="directory_server_type_homeserver">Type a homeserver to list public rooms from</string>
-    <string name="directory_server_placeholder">Homeserver URL</string>
+    <string name="directory_server_placeholder">Server name</string>
     <string name="directory_server_all_rooms_on_server">All rooms on %s server</string>
     <string name="directory_server_native_rooms">All native %s rooms</string>
+    <string name="directory_your_server">Your server</string>
+    <string name="directory_add_a_new_server">Add a new server</string>
+    <string name="directory_add_a_new_server_prompt">Enter the name of a new server you want to explore.</string>
+    <string name="directory_add_a_new_server_error">"Can't find this server or its room list"</string>
+    <string name="directory_add_a_new_server_error_already_added">This server is already present in the list</string>
 
     <!-- Lock screen-->
     <string name="lock_screen_hint">Type hereā€¦</string>