From fb337dacd60b5e0305f042855ade8cdab4b323c5 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Thu, 10 Jun 2021 15:42:53 +0200
Subject: [PATCH 1/9] Add space alias in creation wizard

---
 .../api/session/room/RoomDirectoryService.kt  |  4 +
 .../sdk/api/session/space/SpaceService.kt     |  6 +-
 .../room/DefaultRoomDirectoryService.kt       | 18 +++-
 .../alias/RoomAliasAvailabilityChecker.kt     |  4 +-
 .../session/space/DefaultSpaceService.kt      |  3 +-
 .../app/features/form/FormEditTextItem.kt     | 24 +++++-
 .../features/spaces/SpaceCreationActivity.kt  |  3 +
 .../spaces/create/CreateSpaceAction.kt        |  1 +
 .../create/CreateSpaceDetailsFragment.kt      |  4 +
 .../spaces/create/CreateSpaceEvents.kt        |  1 +
 .../spaces/create/CreateSpaceState.kt         |  4 +
 .../spaces/create/CreateSpaceViewModel.kt     | 82 +++++++++++++++++--
 .../spaces/create/CreateSpaceViewModelTask.kt |  4 +-
 .../create/SpaceDetailEpoxyController.kt      | 50 ++++++++---
 vector/src/main/res/values/strings.xml        |  1 +
 15 files changed, 183 insertions(+), 26 deletions(-)

diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
index 176de8e408..cb74115f54 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
@@ -16,6 +16,8 @@
 
 package org.matrix.android.sdk.api.session.room
 
+import arrow.core.Either
+import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
@@ -40,4 +42,6 @@ interface RoomDirectoryService {
      * Set the visibility of a room in the directory
      */
     suspend fun setRoomDirectoryVisibility(roomId: String, roomDirectoryVisibility: RoomDirectoryVisibility)
+
+    suspend fun checkAliasAvailability(aliasLocalPart: String?) : Result<Unit>
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
index fedf38fe06..e5288e4045 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
@@ -36,7 +36,11 @@ interface SpaceService {
     /**
      * Just a shortcut for space creation for ease of use
      */
-    suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String
+    suspend fun createSpace(name: String,
+                            topic: String?,
+                            avatarUri: Uri?,
+                            isPublic: Boolean,
+                            roomAliasLocalPart: String? = null): String
 
     /**
      * Get a space from a roomId
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
index 218d846afb..5cd5d0adb2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
@@ -16,10 +16,15 @@
 
 package org.matrix.android.sdk.internal.session.room
 
+import arrow.core.Either
+import arrow.core.Right
 import org.matrix.android.sdk.api.session.room.RoomDirectoryService
+import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
+import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
+import org.matrix.android.sdk.internal.session.room.alias.RoomAliasAvailabilityChecker
 import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask
 import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask
 import org.matrix.android.sdk.internal.session.room.directory.SetRoomDirectoryVisibilityTask
@@ -28,7 +33,8 @@ import javax.inject.Inject
 internal class DefaultRoomDirectoryService @Inject constructor(
         private val getPublicRoomTask: GetPublicRoomTask,
         private val getRoomDirectoryVisibilityTask: GetRoomDirectoryVisibilityTask,
-        private val setRoomDirectoryVisibilityTask: SetRoomDirectoryVisibilityTask
+        private val setRoomDirectoryVisibilityTask: SetRoomDirectoryVisibilityTask,
+        private val roomAliasAvailabilityChecker: RoomAliasAvailabilityChecker
 ) : RoomDirectoryService {
 
     override suspend fun getPublicRooms(server: String?,
@@ -43,4 +49,14 @@ internal class DefaultRoomDirectoryService @Inject constructor(
     override suspend fun setRoomDirectoryVisibility(roomId: String, roomDirectoryVisibility: RoomDirectoryVisibility) {
         setRoomDirectoryVisibilityTask.execute(SetRoomDirectoryVisibilityTask.Params(roomId, roomDirectoryVisibility))
     }
+
+
+    override suspend fun checkAliasAvailability(aliasLocalPart: String?): Result<Unit> {
+        return try {
+            roomAliasAvailabilityChecker.check(aliasLocalPart)
+            Result.success(Unit)
+        } catch (failure: RoomAliasError) {
+            Result.failure(failure)
+        }
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
index b39cbaa582..66164c5280 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
@@ -51,13 +51,13 @@ internal class RoomAliasAvailabilityChecker @Inject constructor(
         } catch (throwable: Throwable) {
             if (throwable is Failure.ServerError && throwable.httpCode == 404) {
                 // This is a 404, so the alias is available: nominal case
-                null
+                return
             } else {
                 // Other error, propagate it
                 throw throwable
             }
         }
-                ?.let {
+                .let {
                     // Alias already exists: error case
                     throw RoomAliasError.AliasNotAvailable
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
index 9c6153b349..0c5c0416f9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
@@ -66,12 +66,13 @@ internal class DefaultSpaceService @Inject constructor(
         return createRoomTask.executeRetry(params, 3)
     }
 
-    override suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String {
+    override suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean, roomAliasLocalPart: String?): String {
         return createSpace(CreateSpaceParams().apply {
             this.name = name
             this.topic = topic
             this.avatarUri = avatarUri
             if (isPublic) {
+                this.roomAliasName = roomAliasLocalPart
                 this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
                         invite = 0
                 )
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 e2203057ab..8960ddcd02 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
@@ -40,6 +40,9 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
     @EpoxyAttribute
     var value: String? = null
 
+    @EpoxyAttribute
+    var forceUpdateValue: Boolean = false
+
     @EpoxyAttribute
     var errorMessage: String? = null
 
@@ -64,12 +67,23 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
     @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
     var editorActionListener: TextView.OnEditorActionListener? = null
 
+    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
+    var onFocusChange: ((Boolean) -> Unit)? = null
+
+    @EpoxyAttribute
+    var inputPrefix: String? = null
+
+    @EpoxyAttribute
+    var inputSuffix: String? = null
+
     private val onTextChangeListener = object : SimpleTextWatcher() {
         override fun afterTextChanged(s: Editable) {
             onTextChange?.invoke(s.toString())
         }
     }
 
+    private val onFocusChangedListener = View.OnFocusChangeListener { _, hasFocus -> onFocusChange?.invoke(hasFocus) }
+
     override fun bind(holder: Holder) {
         super.bind(holder)
         holder.textInputLayout.isEnabled = enabled
@@ -77,7 +91,14 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
         holder.textInputLayout.error = errorMessage
         holder.textInputLayout.endIconMode = endIconMode ?: TextInputLayout.END_ICON_NONE
 
-        holder.setValueOnce(holder.textInputEditText, value)
+        holder.textInputLayout.prefixText = inputPrefix
+        holder.textInputLayout.suffixText = inputSuffix
+
+        if (forceUpdateValue) {
+            holder.textInputEditText.setText(value)
+        } else {
+            holder.setValueOnce(holder.textInputEditText, value)
+        }
 
         holder.textInputEditText.isEnabled = enabled
         inputType?.let { holder.textInputEditText.inputType = it }
@@ -86,6 +107,7 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
 
         holder.textInputEditText.addTextChangedListenerOnce(onTextChangeListener)
         holder.textInputEditText.setOnEditorActionListener(editorActionListener)
+        holder.textInputEditText.onFocusChangeListener = onFocusChangedListener
     }
 
     override fun shouldSaveViewState(): Boolean {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt
index 6bf31dd5ce..a02755a155 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt
@@ -113,6 +113,9 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
                 CreateSpaceEvents.HideModalLoading            -> {
                     hideWaitingView()
                 }
+                is CreateSpaceEvents.ShowModalLoading         -> {
+                    showWaitingView(it.message)
+                }
             }
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAction.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAction.kt
index cd31b40354..1f0ed6428f 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAction.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceAction.kt
@@ -23,6 +23,7 @@ sealed class CreateSpaceAction : VectorViewModelAction {
     data class SetRoomType(val type: SpaceType) : CreateSpaceAction()
     data class NameChanged(val name: String) : CreateSpaceAction()
     data class TopicChanged(val topic: String) : CreateSpaceAction()
+    data class SpaceAliasChanged(val aliasLocalPart: String) : CreateSpaceAction()
     data class SetAvatar(val uri: Uri?) : CreateSpaceAction()
     object OnBackPressed : CreateSpaceAction()
     object NextFromDetails : CreateSpaceAction()
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt
index b5925eec59..544c33948b 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceDetailsFragment.kt
@@ -84,6 +84,10 @@ class CreateSpaceDetailsFragment @Inject constructor(
         sharedViewModel.handle(CreateSpaceAction.TopicChanged(newTopic))
     }
 
+    override fun setAliasLocalPart(aliasLocalPart: String) {
+        sharedViewModel.handle(CreateSpaceAction.SpaceAliasChanged(aliasLocalPart))
+    }
+
     override fun onBackPressed(toolbarButton: Boolean): Boolean {
         sharedViewModel.handle(CreateSpaceAction.OnBackPressed)
         return true
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceEvents.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceEvents.kt
index c3fa2b2068..073531353f 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceEvents.kt
@@ -27,4 +27,5 @@ sealed class CreateSpaceEvents : VectorViewEvents {
     data class FinishSuccess(val spaceId: String, val defaultRoomId: String?, val topology: SpaceTopology?) : CreateSpaceEvents()
     data class ShowModalError(val errorMessage: String) : CreateSpaceEvents()
     object HideModalLoading : CreateSpaceEvents()
+    data class ShowModalLoading(val message: String?) : CreateSpaceEvents()
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt
index 147fd3a616..39a69e837b 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt
@@ -28,6 +28,10 @@ data class CreateSpaceState(
         val step: Step = Step.ChooseType,
         val spaceType: SpaceType? = null,
         val spaceTopology: SpaceTopology? = null,
+        val homeServerName: String? = null,
+        val aliasLocalPart: String? = null,
+        val aliasManuallyModified: Boolean = false,
+        val aliasVerificationTask: Async<Boolean> = Uninitialized,
         val nameInlineError: String? = null,
         val defaultRooms: Map<Int /** position in form */, String?>? = null,
         val creationResult: Async<String> = Uninitialized
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
index aff342cea7..7b430dd411 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
@@ -35,14 +35,25 @@ import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 
 class CreateSpaceViewModel @AssistedInject constructor(
         @Assisted initialState: CreateSpaceState,
+        private val session: Session,
         private val stringProvider: StringProvider,
         private val createSpaceViewModelTask: CreateSpaceViewModelTask,
         private val errorFormatter: ErrorFormatter
 ) : VectorViewModel<CreateSpaceState, CreateSpaceAction, CreateSpaceEvents>(initialState) {
 
+    init {
+        setState {
+            copy(
+                    homeServerName = session.myUserId.substringAfter(":")
+            )
+        }
+    }
+
     @AssistedFactory
     interface Factory {
         fun create(initialState: CreateSpaceState): CreateSpaceViewModel
@@ -80,10 +91,15 @@ class CreateSpaceViewModel @AssistedInject constructor(
                 _viewEvents.post(CreateSpaceEvents.NavigateToDetails)
             }
             is CreateSpaceAction.NameChanged            -> {
+                val tentativeAlias =
+                        getAliasFromName(action.name)
+
                 setState {
                     copy(
                             nameInlineError = null,
-                            name = action.name
+                            name = action.name,
+                            aliasLocalPart = tentativeAlias,
+                            aliasVerificationTask = Uninitialized
                     )
                 }
             }
@@ -94,6 +110,15 @@ class CreateSpaceViewModel @AssistedInject constructor(
                     )
                 }
             }
+            is CreateSpaceAction.SpaceAliasChanged      -> {
+                setState {
+                    copy(
+                            aliasManuallyModified = true,
+                            aliasLocalPart = action.aliasLocalPart,
+                            aliasVerificationTask = Uninitialized
+                    )
+                }
+            }
             CreateSpaceAction.OnBackPressed             -> {
                 handleBackNavigation()
             }
@@ -121,6 +146,12 @@ class CreateSpaceViewModel @AssistedInject constructor(
         }.exhaustive
     }
 
+    private fun getAliasFromName(name: String): String {
+        return Regex("\\s").replace(name.lowercase(), "_").let {
+            "[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
+        }
+    }
+
     private fun handleSetTopology(action: CreateSpaceAction.SetSpaceTopology) {
         when (action.topology) {
             SpaceTopology.JustMe         -> {
@@ -204,12 +235,31 @@ class CreateSpaceViewModel @AssistedInject constructor(
                 }
                 _viewEvents.post(CreateSpaceEvents.NavigateToChoosePrivateType)
             } else {
+                // it'a public space, let's check alias
+                val aliasLocalPart = if (state.aliasManuallyModified) state.aliasLocalPart else getAliasFromName(state.name)
+                _viewEvents.post(CreateSpaceEvents.ShowModalLoading(null))
                 setState {
-                    copy(
-                            step = CreateSpaceState.Step.AddRooms
+                    copy(aliasVerificationTask = Loading())
+                }
+                viewModelScope.launch {
+                    session.checkAliasAvailability(aliasLocalPart).fold(
+                            {
+                                setState {
+                                    copy(
+                                            step = CreateSpaceState.Step.AddRooms
+                                    )
+                                }
+                                _viewEvents.post(CreateSpaceEvents.HideModalLoading)
+                                _viewEvents.post(CreateSpaceEvents.NavigateToAddRooms)
+                            },
+                            {
+                                setState {
+                                    copy(aliasVerificationTask = Fail(it))
+                                }
+                                _viewEvents.post(CreateSpaceEvents.HideModalLoading)
+                            }
                     )
                 }
-                _viewEvents.post(CreateSpaceEvents.NavigateToAddRooms)
             }
         }
     }
@@ -221,6 +271,9 @@ class CreateSpaceViewModel @AssistedInject constructor(
         }
         viewModelScope.launch(Dispatchers.IO) {
             try {
+                val alias = if (state.spaceType == SpaceType.Public) {
+                    if (state.aliasManuallyModified) state.aliasLocalPart else getAliasFromName(state.name)
+                } else null
                 val result = createSpaceViewModelTask.execute(
                         CreateSpaceTaskParams(
                                 spaceName = spaceName,
@@ -230,7 +283,8 @@ class CreateSpaceViewModel @AssistedInject constructor(
                                 defaultRooms = state.defaultRooms
                                         ?.entries
                                         ?.sortedBy { it.key }
-                                        ?.mapNotNull { it.value } ?: emptyList()
+                                        ?.mapNotNull { it.value } ?: emptyList(),
+                                spaceAlias = alias
                         )
                 )
                 when (result) {
@@ -260,10 +314,22 @@ class CreateSpaceViewModel @AssistedInject constructor(
                         )
                     }
                     is CreateSpaceTaskResult.FailedToCreateSpace -> {
-                        setState {
-                            copy(creationResult = Fail(result.failure))
+                        if (result.failure is CreateRoomFailure.AliasError) {
+                            setState {
+                                copy(
+                                        step = CreateSpaceState.Step.SetDetails,
+                                        aliasVerificationTask = Fail(result.failure.aliasError),
+                                        creationResult = Uninitialized
+                                )
+                            }
+                            _viewEvents.post(CreateSpaceEvents.HideModalLoading)
+                            _viewEvents.post(CreateSpaceEvents.NavigateToDetails)
+                        } else {
+                            setState {
+                                copy(creationResult = Fail(result.failure))
+                            }
+                            _viewEvents.post(CreateSpaceEvents.ShowModalError(errorFormatter.toHumanReadable(result.failure)))
                         }
-                        _viewEvents.post(CreateSpaceEvents.ShowModalError(errorFormatter.toHumanReadable(result.failure)))
                     }
                 }
             } catch (failure: Throwable) {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt
index 9ce1089f6c..ae9ab4ca63 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt
@@ -45,6 +45,7 @@ data class CreateSpaceTaskParams(
         val spaceName: String,
         val spaceTopic: String?,
         val spaceAvatar: Uri? = null,
+        val spaceAlias: String? = null,
         val isPublic: Boolean,
         val defaultRooms: List<String> = emptyList()
 )
@@ -57,7 +58,8 @@ class CreateSpaceViewModelTask @Inject constructor(
 
     override suspend fun execute(params: CreateSpaceTaskParams): CreateSpaceTaskResult {
         val spaceID = try {
-            session.spaceService().createSpace(params.spaceName, params.spaceTopic, params.spaceAvatar, params.isPublic)
+            session.spaceService().createSpace(params.spaceName, params.spaceTopic, params.spaceAvatar,
+                    params.isPublic, params.spaceAlias)
         } catch (failure: Throwable) {
             return CreateSpaceTaskResult.FailedToCreateSpace(failure)
         }
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 9b3686c513..36a04ef6fa 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
@@ -17,24 +17,39 @@
 package im.vector.app.features.spaces.create
 
 import com.airbnb.epoxy.TypedEpoxyController
+import com.airbnb.mvrx.Fail
 import im.vector.app.R
+import im.vector.app.core.epoxy.TextListener
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.core.ui.list.genericFooterItem
 import im.vector.app.features.form.formEditTextItem
 import im.vector.app.features.form.formEditableSquareAvatarItem
 import im.vector.app.features.form.formMultiLineEditTextItem
 import im.vector.app.features.home.AvatarRenderer
+import im.vector.app.features.roomdirectory.createroom.RoomAliasErrorFormatter
+import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
 import org.matrix.android.sdk.api.util.MatrixItem
 import javax.inject.Inject
 
 class SpaceDetailEpoxyController @Inject constructor(
         private val stringProvider: StringProvider,
-        private val avatarRenderer: AvatarRenderer
+        private val avatarRenderer: AvatarRenderer,
+        private val roomAliasErrorFormatter: RoomAliasErrorFormatter
 ) : TypedEpoxyController<CreateSpaceState>() {
 
     var listener: Listener? = null
 
-//    var shouldForceFocusOnce = true
+    /**
+     * Alias text can be automatically set when changing the room name,
+     * We have to be able to make a difference between a programming change versus
+     * a user change.
+     */
+    var aliasTextIsFocused = false
+    private val aliasTextWatcher: TextListener = {
+        if (aliasTextIsFocused) {
+            listener?.setAliasLocalPart(it)
+        }
+    }
 
     override fun buildModels(data: CreateSpaceState?) {
         val host = this
@@ -65,20 +80,32 @@ class SpaceDetailEpoxyController @Inject constructor(
             value(data?.name)
             hint(host.stringProvider.getString(R.string.create_room_name_hint))
             errorMessage(data?.nameInlineError)
-//            onBind { _, view, _ ->
-//                if (shouldForceFocusOnce && data?.name.isNullOrBlank()) {
-//                    shouldForceFocusOnce = false
-//                    // sad face :(
-//                    view.textInputEditText.post {
-//                        view.textInputEditText.showKeyboard(true)
-//                    }
-//                }
-//            }
             onTextChange { text ->
                 host.listener?.onNameChange(text)
             }
         }
 
+        if (data?.spaceType == SpaceType.Public) {
+            formEditTextItem {
+                id("alias")
+                enabled(true)
+                forceUpdateValue(!data.aliasManuallyModified)
+                value(data.aliasLocalPart)
+                hint(host.stringProvider.getString(R.string.create_space_alias_hint))
+                inputSuffix(":" + data.homeServerName)
+                inputPrefix("#")
+                onFocusChange { hasFocus ->
+                    host.aliasTextIsFocused = hasFocus
+                }
+                errorMessage(
+                        host.roomAliasErrorFormatter.format(
+                                (((data.aliasVerificationTask as? Fail)?.error) as? RoomAliasError))
+                )
+                onTextChange(host.aliasTextWatcher)
+                showBottomSeparator(false)
+            }
+        }
+
         formMultiLineEditTextItem {
             id("topic")
             enabled(true)
@@ -96,5 +123,6 @@ class SpaceDetailEpoxyController @Inject constructor(
         fun onAvatarChange()
         fun onNameChange(newName: String)
         fun onTopicChange(newTopic: String)
+        fun setAliasLocalPart(aliasLocalPart: String)
     }
 }
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 621ecb7aee..0f012ef31d 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -2585,6 +2585,7 @@
     <string name="create_room_disable_federation_description">You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.</string>
 
     <string name="create_room_alias_hint">Room address</string>
+    <string name="create_space_alias_hint">Space address</string>
     <string name="create_room_alias_already_in_use">This address is already in use</string>
     <string name="create_room_alias_empty">Please provide a room address</string>
     <string name="create_room_alias_invalid">Some characters are not allowed</string>

From b1ab6eb58f3eaa23b475f00a8728c338a3116c57 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Thu, 10 Jun 2021 16:17:24 +0200
Subject: [PATCH 2/9] Add alias management in space settings

---
 .../sdk/api/session/room/RoomDirectoryService.kt     |  2 --
 .../session/room/DefaultRoomDirectoryService.kt      |  4 ----
 .../roomprofile/alias/RoomAliasController.kt         |  5 ++++-
 .../features/spaces/manage/SpaceManageActivity.kt    | 10 ++++++++++
 .../spaces/manage/SpaceManageSharedViewModel.kt      |  1 +
 .../spaces/manage/SpaceManagedSharedAction.kt        |  1 +
 .../spaces/manage/SpaceManagedSharedViewEvents.kt    |  1 +
 .../spaces/manage/SpaceSettingsController.kt         | 12 ++++++++++++
 .../features/spaces/manage/SpaceSettingsFragment.kt  |  4 ++++
 vector/src/main/res/values/strings.xml               |  2 ++
 10 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
index cb74115f54..4b19e7ba96 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
@@ -16,8 +16,6 @@
 
 package org.matrix.android.sdk.api.session.room
 
-import arrow.core.Either
-import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
index 5cd5d0adb2..7da1da27ed 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
@@ -16,11 +16,8 @@
 
 package org.matrix.android.sdk.internal.session.room
 
-import arrow.core.Either
-import arrow.core.Right
 import org.matrix.android.sdk.api.session.room.RoomDirectoryService
 import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
-import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsResponse
@@ -50,7 +47,6 @@ internal class DefaultRoomDirectoryService @Inject constructor(
         setRoomDirectoryVisibilityTask.execute(SetRoomDirectoryVisibilityTask.Params(roomId, roomDirectoryVisibility))
     }
 
-
     override suspend fun checkAliasAvailability(aliasLocalPart: String?): Result<Unit> {
         return try {
             roomAliasAvailabilityChecker.check(aliasLocalPart)
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
index 97050e9c6d..0689cf2f56 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
@@ -39,6 +39,7 @@ import im.vector.app.features.roomdirectory.createroom.RoomAliasErrorFormatter
 import im.vector.app.features.roomdirectory.createroom.roomAliasEditItem
 import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
+import org.matrix.android.sdk.api.session.room.model.RoomType
 import javax.inject.Inject
 
 class RoomAliasController @Inject constructor(
@@ -71,7 +72,9 @@ class RoomAliasController @Inject constructor(
         // Published alias
         buildPublishInfo(data)
         // Room directory visibility
-        buildRoomDirectoryVisibility(data)
+        if (data.roomSummary.invoke()?.roomType != RoomType.SPACE) {
+            buildRoomDirectoryVisibility(data)
+        }
         // Local alias
         buildLocalInfo(data)
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt
index 334c7bd64d..630c578069 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt
@@ -39,6 +39,7 @@ import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
 import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs
 import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
 import im.vector.app.features.roomprofile.RoomProfileArgs
+import im.vector.app.features.roomprofile.alias.RoomAliasFragment
 import kotlinx.parcelize.Parcelize
 import javax.inject.Inject
 
@@ -155,6 +156,15 @@ class SpaceManageActivity : VectorBaseActivity<ActivitySimpleLoadingBinding>(),
                         )
                     }
                 }
+                SpaceManagedSharedViewEvents.NavigateToAliasSettings -> {
+                    args?.spaceId?.let { spaceId ->
+                        addFragmentToBackstack(
+                                R.id.simpleFragmentContainer,
+                                RoomAliasFragment::class.java,
+                                RoomProfileArgs(spaceId)
+                        )
+                    }
+                }
             }
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt
index 57c47250f9..f1d041056f 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt
@@ -56,6 +56,7 @@ class SpaceManageSharedViewModel @AssistedInject constructor(
             SpaceManagedSharedAction.ShowLoading -> _viewEvents.post(SpaceManagedSharedViewEvents.ShowLoading)
             SpaceManagedSharedAction.CreateRoom ->  _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToCreateRoom)
             SpaceManagedSharedAction.ManageRooms -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToManageRooms)
+            SpaceManagedSharedAction.OpenSpaceAliasesSettings -> _viewEvents.post(SpaceManagedSharedViewEvents.NavigateToAliasSettings)
         }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt
index 0b413a3b8a..77143470bc 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedAction.kt
@@ -24,4 +24,5 @@ sealed class SpaceManagedSharedAction : VectorViewModelAction {
     object HideLoading : SpaceManagedSharedAction()
     object CreateRoom : SpaceManagedSharedAction()
     object ManageRooms : SpaceManagedSharedAction()
+    object OpenSpaceAliasesSettings : SpaceManagedSharedAction()
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt
index da6f01d205..ab993764c6 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManagedSharedViewEvents.kt
@@ -24,4 +24,5 @@ sealed class SpaceManagedSharedViewEvents : VectorViewEvents {
     object HideLoading : SpaceManagedSharedViewEvents()
     object NavigateToCreateRoom : SpaceManagedSharedViewEvents()
     object NavigateToManageRooms : SpaceManagedSharedViewEvents()
+    object NavigateToAliasSettings : SpaceManagedSharedViewEvents()
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
index 08b21db025..10dd11527d 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
@@ -52,6 +52,7 @@ class SpaceSettingsController @Inject constructor(
         fun onDevRoomSettings()
         fun onManageRooms()
         fun setIsPublic(public: Boolean)
+        fun onRoomAliasesClicked()
     }
 
     var callback: Callback? = null
@@ -139,6 +140,17 @@ class SpaceSettingsController @Inject constructor(
                     if (data.actionPermissions.canAddChildren) callback?.onManageRooms()
                 }
         )
+        if (roomSummary.isPublic) {
+            buildProfileAction(
+                    id = "alias",
+                    title = stringProvider.getString(R.string.space_settings_alias_title),
+                    subtitle = stringProvider.getString(R.string.space_settings_alias_subtitle),
+                    dividerColor = dividerColor,
+                    divider = true,
+                    editable = true,
+                    action = { callback?.onRoomAliasesClicked() }
+            )
+        }
 
         if (vectorPreferences.developerMode()) {
             buildProfileAction(
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt
index 350c0bdb4a..e831732bcc 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt
@@ -233,6 +233,10 @@ class SpaceSettingsFragment @Inject constructor(
         }
     }
 
+    override fun onRoomAliasesClicked() {
+        sharedViewModel.handle(SpaceManagedSharedAction.OpenSpaceAliasesSettings)
+    }
+
     override fun onImageReady(uri: Uri?) {
         uri ?: return
         viewModel.handle(
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 0f012ef31d..54356db664 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -1414,6 +1414,8 @@
     <!-- room settings : alias -->
     <string name="room_settings_alias_title">Room addresses</string>
     <string name="room_settings_alias_subtitle">See and managed addresses of this room, and its visibility in the room directory.</string>
+    <string name="space_settings_alias_title">Space addresses</string>
+    <string name="space_settings_alias_subtitle">See and managed addresses of this space.</string>
 
     <string name="room_alias_title">Room Addresses</string>
     <string name="room_alias_published_alias_title">Published Addresses</string>

From 28a6caf754bd8e8331afc0f9bf9c58b14fbbf9d4 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Thu, 10 Jun 2021 17:07:58 +0200
Subject: [PATCH 3/9] cleaning + rebase

---
 .../app/features/form/FormEditTextItem.kt     |  1 +
 .../createroom/CreateRoomController.kt        |  6 +-
 .../createroom/RoomAliasEditItem.kt           | 82 -------------------
 .../roomprofile/alias/RoomAliasController.kt  |  7 +-
 .../create/SpaceDetailEpoxyController.kt      |  1 -
 .../spaces/manage/SpaceSettingsController.kt  |  8 +-
 .../res/layout/item_room_alias_text_input.xml | 54 ------------
 7 files changed, 13 insertions(+), 146 deletions(-)
 delete mode 100644 vector/src/main/java/im/vector/app/features/roomdirectory/createroom/RoomAliasEditItem.kt
 delete mode 100644 vector/src/main/res/layout/item_room_alias_text_input.xml

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 8960ddcd02..5607ddcd5d 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
@@ -17,6 +17,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 com.airbnb.epoxy.EpoxyAttribute
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 61b34a1499..3ac61f1803 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
@@ -99,11 +99,13 @@ class CreateRoomController @Inject constructor(
         }
         if (viewState.roomVisibilityType is CreateRoomViewState.RoomVisibilityType.Public) {
             // Room alias for public room
-            roomAliasEditItem {
+            formEditTextItem {
                 id("alias")
                 enabled(enableFormElement)
                 value(viewState.roomVisibilityType.aliasLocalPart)
-                homeServer(":" + viewState.homeServerName)
+                inputSuffix(":" + viewState.homeServerName)
+                inputPrefix("#")
+                hint(host.stringProvider.getString(R.string.room_alias_address_hint))
                 errorMessage(
                         host.roomAliasErrorFormatter.format(
                                 (((viewState.asyncCreateRoomRequest as? Fail)?.error) as? CreateRoomFailure.AliasError)?.aliasError)
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/RoomAliasEditItem.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/RoomAliasEditItem.kt
deleted file mode 100644
index 9cb6f79a56..0000000000
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/RoomAliasEditItem.kt
+++ /dev/null
@@ -1,82 +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.roomdirectory.createroom
-
-import android.text.Editable
-import android.widget.TextView
-import com.airbnb.epoxy.EpoxyAttribute
-import com.airbnb.epoxy.EpoxyModelClass
-import com.google.android.material.textfield.TextInputEditText
-import com.google.android.material.textfield.TextInputLayout
-import im.vector.app.R
-import im.vector.app.core.epoxy.TextListener
-import im.vector.app.core.epoxy.VectorEpoxyHolder
-import im.vector.app.core.epoxy.VectorEpoxyModel
-import im.vector.app.core.epoxy.addTextChangedListenerOnce
-import im.vector.app.core.epoxy.setValueOnce
-import im.vector.app.core.platform.SimpleTextWatcher
-
-@EpoxyModelClass(layout = R.layout.item_room_alias_text_input)
-abstract class RoomAliasEditItem : VectorEpoxyModel<RoomAliasEditItem.Holder>() {
-
-    @EpoxyAttribute
-    var value: String? = null
-
-    @EpoxyAttribute
-    var errorMessage: String? = null
-
-    @EpoxyAttribute
-    var homeServer: String? = null
-
-    @EpoxyAttribute
-    var enabled: Boolean = true
-
-    @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
-    var onTextChange: TextListener? = null
-
-    private val onTextChangeListener = object : SimpleTextWatcher() {
-        override fun afterTextChanged(s: Editable) {
-            onTextChange?.invoke(s.toString())
-        }
-    }
-
-    override fun bind(holder: Holder) {
-        super.bind(holder)
-        holder.textInputLayout.isEnabled = enabled
-        holder.textInputLayout.error = errorMessage
-
-        holder.setValueOnce(holder.textInputEditText, value)
-        holder.textInputEditText.isEnabled = enabled
-        holder.textInputEditText.addTextChangedListenerOnce(onTextChangeListener)
-        holder.homeServerText.text = homeServer
-    }
-
-    override fun shouldSaveViewState(): Boolean {
-        return false
-    }
-
-    override fun unbind(holder: Holder) {
-        super.unbind(holder)
-        holder.textInputEditText.removeTextChangedListener(onTextChangeListener)
-    }
-
-    class Holder : VectorEpoxyHolder() {
-        val textInputLayout by bind<TextInputLayout>(R.id.itemRoomAliasTextInputLayout)
-        val textInputEditText by bind<TextInputEditText>(R.id.itemRoomAliasTextInputEditText)
-        val homeServerText by bind<TextView>(R.id.itemRoomAliasHomeServer)
-    }
-}
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
index 0689cf2f56..50bc3d1e5c 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
@@ -36,7 +36,6 @@ import im.vector.app.features.discovery.settingsInfoItem
 import im.vector.app.features.form.formEditTextItem
 import im.vector.app.features.form.formSwitchItem
 import im.vector.app.features.roomdirectory.createroom.RoomAliasErrorFormatter
-import im.vector.app.features.roomdirectory.createroom.roomAliasEditItem
 import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.session.room.model.RoomType
@@ -246,10 +245,12 @@ class RoomAliasController @Inject constructor(
                 }
             }
             is RoomAliasViewState.AddAliasState.Editing -> {
-                roomAliasEditItem {
+                formEditTextItem {
                     id("newLocalAlias")
                     value(data.newLocalAliasState.value)
-                    homeServer(":" + data.homeServerName)
+                    inputSuffix(":" + data.homeServerName)
+                    inputPrefix("#")
+                    hint(host.stringProvider.getString(R.string.room_alias_address_hint))
                     errorMessage(host.roomAliasErrorFormatter.format((data.newLocalAliasState.asyncRequest as? Fail)?.error as? RoomAliasError))
                     onTextChange { value ->
                         host.callback?.setNewLocalAliasLocalPart(value)
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 36a04ef6fa..ad544e2648 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
@@ -102,7 +102,6 @@ class SpaceDetailEpoxyController @Inject constructor(
                                 (((data.aliasVerificationTask as? Fail)?.error) as? RoomAliasError))
                 )
                 onTextChange(host.aliasTextWatcher)
-                showBottomSeparator(false)
             }
         }
 
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
index 10dd11527d..11a4a982a0 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
@@ -104,6 +104,7 @@ class SpaceSettingsController @Inject constructor(
             }
         }
 
+        val isPublic = (data.newRoomJoinRules.newJoinRules ?: data.currentRoomJoinRules) == RoomJoinRules.PUBLIC
         if (vectorPreferences.labsUseExperimentalRestricted()) {
             buildProfileAction(
                     id = "joinRule",
@@ -114,7 +115,6 @@ class SpaceSettingsController @Inject constructor(
                     action = { if (data.actionPermissions.canChangeJoinRule) callback?.onJoinRuleClicked() }
             )
         } else {
-            val isPublic = (data.newRoomJoinRules.newJoinRules ?: data.currentRoomJoinRules) == RoomJoinRules.PUBLIC
             formSwitchItem {
                 id("isPublic")
                 enabled(data.actionPermissions.canChangeJoinRule)
@@ -134,18 +134,18 @@ class SpaceSettingsController @Inject constructor(
                 id = "manage_rooms",
                 title = stringProvider.getString(R.string.space_settings_manage_rooms),
                 // subtitle = data.getJoinRuleWording(stringProvider),
-                divider = vectorPreferences.developerMode(),
+                divider = true,
                 editable = data.actionPermissions.canAddChildren,
                 action = {
                     if (data.actionPermissions.canAddChildren) callback?.onManageRooms()
                 }
         )
-        if (roomSummary.isPublic) {
+
+        if (isPublic) {
             buildProfileAction(
                     id = "alias",
                     title = stringProvider.getString(R.string.space_settings_alias_title),
                     subtitle = stringProvider.getString(R.string.space_settings_alias_subtitle),
-                    dividerColor = dividerColor,
                     divider = true,
                     editable = true,
                     action = { callback?.onRoomAliasesClicked() }
diff --git a/vector/src/main/res/layout/item_room_alias_text_input.xml b/vector/src/main/res/layout/item_room_alias_text_input.xml
deleted file mode 100644
index 1cac4763c4..0000000000
--- a/vector/src/main/res/layout/item_room_alias_text_input.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="?android:colorBackground"
-    android:minHeight="@dimen/item_form_min_height">
-
-    <TextView
-        android:id="@+id/itemRoomAliasHash"
-        style="@style/Widget.Vector.TextView.HeadlineMedium"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/layout_horizontal_margin"
-        android:text="@string/matrix_room_alias_prefix"
-        app:layout_constraintBaseline_toBaselineOf="@+id/itemRoomAliasTextInputLayout"
-        app:layout_constraintStart_toStartOf="parent" />
-
-    <com.google.android.material.textfield.TextInputLayout
-        android:id="@+id/itemRoomAliasTextInputLayout"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="8dp"
-        android:layout_marginEnd="8dp"
-        app:errorEnabled="true"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toStartOf="@+id/itemRoomAliasHomeServer"
-        app:layout_constraintStart_toEndOf="@+id/itemRoomAliasHash"
-        app:layout_constraintTop_toTopOf="parent">
-
-        <!-- android:imeOptions="actionDone" to fix a crash -->
-        <com.google.android.material.textfield.TextInputEditText
-            android:id="@+id/itemRoomAliasTextInputEditText"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:hint="@string/create_room_alias_hint"
-            android:imeOptions="actionDone"
-            android:inputType="text" />
-
-    </com.google.android.material.textfield.TextInputLayout>
-
-    <TextView
-        android:id="@+id/itemRoomAliasHomeServer"
-        style="@style/Widget.Vector.TextView.HeadlineMedium"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/layout_horizontal_margin"
-        android:maxWidth="200dp"
-        app:layout_constraintBaseline_toBaselineOf="@+id/itemRoomAliasTextInputLayout"
-        app:layout_constraintEnd_toEndOf="parent"
-        tools:text=":matrix.org" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>

From b6b80120b2d2084139ded75f2231d8fb4bf55037 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Thu, 10 Jun 2021 17:13:26 +0200
Subject: [PATCH 4/9] update change log

---
 newsfragment/3483.feature | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 newsfragment/3483.feature

diff --git a/newsfragment/3483.feature b/newsfragment/3483.feature
new file mode 100644
index 0000000000..e6c27992ea
--- /dev/null
+++ b/newsfragment/3483.feature
@@ -0,0 +1 @@
+Add option to set aliases for public spaces
\ No newline at end of file

From 88119a15bf5cab5cb9de6046f756ebed00d232f0 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Tue, 15 Jun 2021 11:22:29 +0200
Subject: [PATCH 5/9] Core review rename input Suffix|Prefix

---
 .../java/im/vector/app/features/form/FormEditTextItem.kt  | 8 ++++----
 .../roomdirectory/createroom/CreateRoomController.kt      | 4 ++--
 .../app/features/roomprofile/alias/RoomAliasController.kt | 4 ++--
 .../features/spaces/create/SpaceDetailEpoxyController.kt  | 4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

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 5607ddcd5d..2b2fddd0c9 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
@@ -72,10 +72,10 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
     var onFocusChange: ((Boolean) -> Unit)? = null
 
     @EpoxyAttribute
-    var inputPrefix: String? = null
+    var prefixText: String? = null
 
     @EpoxyAttribute
-    var inputSuffix: String? = null
+    var suffixText: String? = null
 
     private val onTextChangeListener = object : SimpleTextWatcher() {
         override fun afterTextChanged(s: Editable) {
@@ -92,8 +92,8 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
         holder.textInputLayout.error = errorMessage
         holder.textInputLayout.endIconMode = endIconMode ?: TextInputLayout.END_ICON_NONE
 
-        holder.textInputLayout.prefixText = inputPrefix
-        holder.textInputLayout.suffixText = inputSuffix
+        holder.textInputLayout.prefixText = prefixText
+        holder.textInputLayout.suffixText = suffixText
 
         if (forceUpdateValue) {
             holder.textInputEditText.setText(value)
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 3ac61f1803..6c441c355c 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
@@ -103,8 +103,8 @@ class CreateRoomController @Inject constructor(
                 id("alias")
                 enabled(enableFormElement)
                 value(viewState.roomVisibilityType.aliasLocalPart)
-                inputSuffix(":" + viewState.homeServerName)
-                inputPrefix("#")
+                suffixText(":" + viewState.homeServerName)
+                prefixText("#")
                 hint(host.stringProvider.getString(R.string.room_alias_address_hint))
                 errorMessage(
                         host.roomAliasErrorFormatter.format(
diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
index 50bc3d1e5c..4a683b6292 100644
--- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasController.kt
@@ -248,8 +248,8 @@ class RoomAliasController @Inject constructor(
                 formEditTextItem {
                     id("newLocalAlias")
                     value(data.newLocalAliasState.value)
-                    inputSuffix(":" + data.homeServerName)
-                    inputPrefix("#")
+                    suffixText(":" + data.homeServerName)
+                    prefixText("#")
                     hint(host.stringProvider.getString(R.string.room_alias_address_hint))
                     errorMessage(host.roomAliasErrorFormatter.format((data.newLocalAliasState.asyncRequest as? Fail)?.error as? RoomAliasError))
                     onTextChange { value ->
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 ad544e2648..27c08d1f6f 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
@@ -92,8 +92,8 @@ class SpaceDetailEpoxyController @Inject constructor(
                 forceUpdateValue(!data.aliasManuallyModified)
                 value(data.aliasLocalPart)
                 hint(host.stringProvider.getString(R.string.create_space_alias_hint))
-                inputSuffix(":" + data.homeServerName)
-                inputPrefix("#")
+                suffixText(":" + data.homeServerName)
+                prefixText("#")
                 onFocusChange { hasFocus ->
                     host.aliasTextIsFocused = hasFocus
                 }

From 9190e1bfb5f12a5cb37c2d06188f042522a95d65 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Tue, 15 Jun 2021 11:22:44 +0200
Subject: [PATCH 6/9] Code Review Formatting

---
 .../features/spaces/create/CreateSpaceViewModelTask.kt   | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt
index ae9ab4ca63..f1731caf76 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModelTask.kt
@@ -58,8 +58,13 @@ class CreateSpaceViewModelTask @Inject constructor(
 
     override suspend fun execute(params: CreateSpaceTaskParams): CreateSpaceTaskResult {
         val spaceID = try {
-            session.spaceService().createSpace(params.spaceName, params.spaceTopic, params.spaceAvatar,
-                    params.isPublic, params.spaceAlias)
+            session.spaceService().createSpace(
+                    params.spaceName,
+                    params.spaceTopic,
+                    params.spaceAvatar,
+                    params.isPublic,
+                    params.spaceAlias
+            )
         } catch (failure: Throwable) {
             return CreateSpaceTaskResult.FailedToCreateSpace(failure)
         }

From 19a2b56011d4e3d31e53a4cfb816bf32dabdb888 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Tue, 15 Jun 2021 11:22:56 +0200
Subject: [PATCH 7/9] Code review AliasAvailabilityResult

---
 .../session/room/AliasAvailabilityResult.kt   | 24 +++++++++++++++++++
 .../api/session/room/RoomDirectoryService.kt  |  2 +-
 .../room/DefaultRoomDirectoryService.kt       |  7 +++---
 .../spaces/create/CreateSpaceViewModel.kt     | 20 +++++++++++-----
 4 files changed, 43 insertions(+), 10 deletions(-)
 create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt

diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt
new file mode 100644
index 0000000000..d5c0d06215
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.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 org.matrix.android.sdk.api.session.room
+
+import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
+
+sealed class AliasAvailabilityResult {
+    object Available: AliasAvailabilityResult()
+    data class NotAvailable(val roomAliasError: RoomAliasError) : AliasAvailabilityResult()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
index 4b19e7ba96..f3e3913bc1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
@@ -41,5 +41,5 @@ interface RoomDirectoryService {
      */
     suspend fun setRoomDirectoryVisibility(roomId: String, roomDirectoryVisibility: RoomDirectoryVisibility)
 
-    suspend fun checkAliasAvailability(aliasLocalPart: String?) : Result<Unit>
+    suspend fun checkAliasAvailability(aliasLocalPart: String?) : AliasAvailabilityResult
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
index 7da1da27ed..7330c91c20 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
@@ -16,6 +16,7 @@
 
 package org.matrix.android.sdk.internal.session.room
 
+import org.matrix.android.sdk.api.session.room.AliasAvailabilityResult
 import org.matrix.android.sdk.api.session.room.RoomDirectoryService
 import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
@@ -47,12 +48,12 @@ internal class DefaultRoomDirectoryService @Inject constructor(
         setRoomDirectoryVisibilityTask.execute(SetRoomDirectoryVisibilityTask.Params(roomId, roomDirectoryVisibility))
     }
 
-    override suspend fun checkAliasAvailability(aliasLocalPart: String?): Result<Unit> {
+    override suspend fun checkAliasAvailability(aliasLocalPart: String?): AliasAvailabilityResult {
         return try {
             roomAliasAvailabilityChecker.check(aliasLocalPart)
-            Result.success(Unit)
+            AliasAvailabilityResult.Available
         } catch (failure: RoomAliasError) {
-            Result.failure(failure)
+            AliasAvailabilityResult.NotAvailable(failure)
         }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
index 7b430dd411..960d428581 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
@@ -36,6 +36,7 @@ import im.vector.app.core.resources.StringProvider
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.room.AliasAvailabilityResult
 import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
 
 class CreateSpaceViewModel @AssistedInject constructor(
@@ -242,8 +243,9 @@ class CreateSpaceViewModel @AssistedInject constructor(
                     copy(aliasVerificationTask = Loading())
                 }
                 viewModelScope.launch {
-                    session.checkAliasAvailability(aliasLocalPart).fold(
-                            {
+                    try {
+                        when (val result = session.checkAliasAvailability(aliasLocalPart)) {
+                            AliasAvailabilityResult.Available       -> {
                                 setState {
                                     copy(
                                             step = CreateSpaceState.Step.AddRooms
@@ -251,14 +253,20 @@ class CreateSpaceViewModel @AssistedInject constructor(
                                 }
                                 _viewEvents.post(CreateSpaceEvents.HideModalLoading)
                                 _viewEvents.post(CreateSpaceEvents.NavigateToAddRooms)
-                            },
-                            {
+                            }
+                            is AliasAvailabilityResult.NotAvailable -> {
                                 setState {
-                                    copy(aliasVerificationTask = Fail(it))
+                                    copy(aliasVerificationTask = Fail(result.roomAliasError))
                                 }
                                 _viewEvents.post(CreateSpaceEvents.HideModalLoading)
                             }
-                    )
+                        }
+                    } catch (failure: Throwable) {
+                        setState {
+                            copy(aliasVerificationTask = Fail(failure))
+                        }
+                        _viewEvents.post(CreateSpaceEvents.HideModalLoading)
+                    }
                 }
             }
         }

From 301251262d755fc8a576ec38ec66278e9fccd02a Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Tue, 15 Jun 2021 12:20:26 +0200
Subject: [PATCH 8/9] Code review cleaning

---
 .../spaces/create/CreateSpaceViewModel.kt     | 30 ++++++++++++-------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
index 960d428581..1e47f9b690 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
@@ -92,16 +92,24 @@ class CreateSpaceViewModel @AssistedInject constructor(
                 _viewEvents.post(CreateSpaceEvents.NavigateToDetails)
             }
             is CreateSpaceAction.NameChanged            -> {
-                val tentativeAlias =
-                        getAliasFromName(action.name)
 
                 setState {
-                    copy(
-                            nameInlineError = null,
-                            name = action.name,
-                            aliasLocalPart = tentativeAlias,
-                            aliasVerificationTask = Uninitialized
-                    )
+                    if (aliasManuallyModified) {
+                        copy(
+                                nameInlineError = null,
+                                name = action.name,
+                                aliasVerificationTask = Uninitialized
+                        )
+                    } else {
+                        val tentativeAlias =
+                                getAliasFromName(action.name)
+                        copy(
+                                nameInlineError = null,
+                                name = action.name,
+                                aliasLocalPart = tentativeAlias,
+                                aliasVerificationTask = Uninitialized
+                        )
+                    }
                 }
             }
             is CreateSpaceAction.TopicChanged           -> {
@@ -112,6 +120,8 @@ class CreateSpaceViewModel @AssistedInject constructor(
                 }
             }
             is CreateSpaceAction.SpaceAliasChanged      -> {
+                // This called only when the alias is change manually
+                // not when programmatically changed via a change on name
                 setState {
                     copy(
                             aliasManuallyModified = true,
@@ -237,7 +247,7 @@ class CreateSpaceViewModel @AssistedInject constructor(
                 _viewEvents.post(CreateSpaceEvents.NavigateToChoosePrivateType)
             } else {
                 // it'a public space, let's check alias
-                val aliasLocalPart = if (state.aliasManuallyModified) state.aliasLocalPart else getAliasFromName(state.name)
+                val aliasLocalPart = state.aliasLocalPart
                 _viewEvents.post(CreateSpaceEvents.ShowModalLoading(null))
                 setState {
                     copy(aliasVerificationTask = Loading())
@@ -280,7 +290,7 @@ class CreateSpaceViewModel @AssistedInject constructor(
         viewModelScope.launch(Dispatchers.IO) {
             try {
                 val alias = if (state.spaceType == SpaceType.Public) {
-                    if (state.aliasManuallyModified) state.aliasLocalPart else getAliasFromName(state.name)
+                    state.aliasLocalPart
                 } else null
                 val result = createSpaceViewModelTask.execute(
                         CreateSpaceTaskParams(

From 4180b4ccd3f5fc5ab6214230a0fe4f76fb6b8e44 Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Fri, 18 Jun 2021 10:47:21 +0200
Subject: [PATCH 9/9] Code review

---
 .../java/org/matrix/android/sdk/api/MatrixPatterns.kt  |  6 ++++++
 .../sdk/api/session/room/AliasAvailabilityResult.kt    |  2 +-
 .../app/features/spaces/create/CreateSpaceViewModel.kt | 10 ++--------
 .../features/spaces/manage/SpaceSettingsController.kt  |  4 ++--
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
index 841e833271..7f5f3f54ef 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
@@ -157,4 +157,10 @@ object MatrixPatterns {
     fun isValidOrderString(order: String?) : Boolean {
         return order != null && order.length < 50 && order matches ORDER_STRING_REGEX
     }
+
+    fun candidateAliasFromRoomName(name: String): String {
+        return Regex("\\s").replace(name.lowercase(), "_").let {
+            "[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
+        }
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt
index d5c0d06215..6f607569c0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/AliasAvailabilityResult.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright 2021 The Matrix.org Foundation C.I.C.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
index 1e47f9b690..60110b7dd5 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt
@@ -35,6 +35,7 @@ import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.MatrixPatterns
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.room.AliasAvailabilityResult
 import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
@@ -92,7 +93,6 @@ class CreateSpaceViewModel @AssistedInject constructor(
                 _viewEvents.post(CreateSpaceEvents.NavigateToDetails)
             }
             is CreateSpaceAction.NameChanged            -> {
-
                 setState {
                     if (aliasManuallyModified) {
                         copy(
@@ -102,7 +102,7 @@ class CreateSpaceViewModel @AssistedInject constructor(
                         )
                     } else {
                         val tentativeAlias =
-                                getAliasFromName(action.name)
+                                MatrixPatterns.candidateAliasFromRoomName(action.name)
                         copy(
                                 nameInlineError = null,
                                 name = action.name,
@@ -157,12 +157,6 @@ class CreateSpaceViewModel @AssistedInject constructor(
         }.exhaustive
     }
 
-    private fun getAliasFromName(name: String): String {
-        return Regex("\\s").replace(name.lowercase(), "_").let {
-            "[^a-z0-9._%#@=+-]".toRegex().replace(it, "")
-        }
-    }
-
     private fun handleSetTopology(action: CreateSpaceAction.SetSpaceTopology) {
         when (action.topology) {
             SpaceTopology.JustMe         -> {
diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
index 11a4a982a0..27204be8a6 100644
--- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
+++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsController.kt
@@ -134,7 +134,7 @@ class SpaceSettingsController @Inject constructor(
                 id = "manage_rooms",
                 title = stringProvider.getString(R.string.space_settings_manage_rooms),
                 // subtitle = data.getJoinRuleWording(stringProvider),
-                divider = true,
+                divider = vectorPreferences.developerMode() || isPublic,
                 editable = data.actionPermissions.canAddChildren,
                 action = {
                     if (data.actionPermissions.canAddChildren) callback?.onManageRooms()
@@ -146,7 +146,7 @@ class SpaceSettingsController @Inject constructor(
                     id = "alias",
                     title = stringProvider.getString(R.string.space_settings_alias_title),
                     subtitle = stringProvider.getString(R.string.space_settings_alias_subtitle),
-                    divider = true,
+                    divider = vectorPreferences.developerMode(),
                     editable = true,
                     action = { callback?.onRoomAliasesClicked() }
             )