From fb337dacd60b5e0305f042855ade8cdab4b323c5 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 10 Jun 2021 15:42:53 +0200 Subject: [PATCH] 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 } 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 { + 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() { @EpoxyAttribute var value: String? = null + @EpoxyAttribute + var forceUpdateValue: Boolean = false + @EpoxyAttribute var errorMessage: String? = null @@ -64,12 +67,23 @@ abstract class FormEditTextItem : VectorEpoxyModel() { @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() { 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() { 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 = Uninitialized, val nameInlineError: String? = null, val defaultRooms: Map? = null, val creationResult: Async = 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(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 = 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() { 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 @@ You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later. Room address + Space address This address is already in use Please provide a room address Some characters are not allowed