From 579efb016ae0e1873ac575252d59ab9afc7f1cad Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 16 Nov 2020 17:25:42 +0100 Subject: [PATCH 01/10] Room creation form: add advanced section to disable federation (#1314) --- CHANGES.md | 1 + .../room/model/create/CreateRoomParams.kt | 21 +++++++- .../session/room/create/CreateRoomBody.kt | 4 +- .../room/create/CreateRoomBodyBuilder.kt | 2 +- .../app/core/resources/DrawableProvider.kt | 8 +-- .../features/form/FormAdvancedToggleItem.kt | 51 +++++++++++++++++++ .../createroom/CreateRoomAction.kt | 3 ++ .../createroom/CreateRoomController.kt | 19 +++++++ .../createroom/CreateRoomFragment.kt | 8 +++ .../createroom/CreateRoomViewModel.kt | 29 +++++++++++ .../createroom/CreateRoomViewState.kt | 3 ++ .../res/layout/item_form_advanced_toggle.xml | 34 +++++++++++++ .../src/main/res/layout/item_form_switch.xml | 2 - vector/src/main/res/values/strings.xml | 6 +++ 14 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/form/FormAdvancedToggleItem.kt create mode 100644 vector/src/main/res/layout/item_form_advanced_toggle.xml diff --git a/CHANGES.md b/CHANGES.md index 936e6b0ffe..a3338b2c75 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Improvements 🙌: - Open an existing DM instead of creating a new one (#2319) - Ask for explicit user consent to send their contact details to the identity server (#2375) - Handle events of type "m.room.server_acl" (#890) + - Room creation form: add advanced section to disable federation (#1314) Bugfix 🐛: - Fix issue when restoring draft after sharing (#2287) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt index 892a865751..80e3741a0c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt @@ -94,7 +94,22 @@ class CreateRoomParams { * The server will clobber the following keys: creator. * Future versions of the specification may allow the server to clobber other keys. */ - var creationContent: Any? = null + val creationContent = mutableMapOf() + + /** + * Set to true to disable federation of this room. + * Default: false + */ + var disableFederation = false + set(value) { + field = value + if (value) { + creationContent[CREATION_CONTENT_KEY_M_FEDERATE] = false + } else { + // This is the default value, we remove the field + creationContent.remove(CREATION_CONTENT_KEY_M_FEDERATE) + } + } /** * The power level content to override in the default power level event @@ -120,4 +135,8 @@ class CreateRoomParams { fun enableEncryption() { algorithm = MXCRYPTO_ALGORITHM_MEGOLM } + + companion object { + private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate" + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt index c30f11b9af..13d403e2e4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt @@ -74,8 +74,8 @@ internal data class CreateRoomBody( val invite3pids: List?, /** - * Extra keys to be added to the content of the m.room.create. - * The server will clobber the following keys: creator. + * Extra keys, such as m.federate, to be added to the content of the m.room.create event. + * The server will clobber the following keys: creator, room_version. * Future versions of the specification may allow the server to clobber other keys. */ @Json(name = "creation_content") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index 632fcab70b..79ff9db087 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -81,7 +81,7 @@ internal class CreateRoomBodyBuilder @Inject constructor( topic = params.topic, invitedUserIds = params.invitedUserIds, invite3pids = invite3pids, - creationContent = params.creationContent, + creationContent = params.creationContent.takeIf { it.isNotEmpty() }, initialStates = initialStates, preset = params.preset, isDirect = params.isDirect, diff --git a/vector/src/main/java/im/vector/app/core/resources/DrawableProvider.kt b/vector/src/main/java/im/vector/app/core/resources/DrawableProvider.kt index c184b04bd9..96b1cfbb8e 100644 --- a/vector/src/main/java/im/vector/app/core/resources/DrawableProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/DrawableProvider.kt @@ -26,12 +26,12 @@ import javax.inject.Inject class DrawableProvider @Inject constructor(private val context: Context) { - fun getDrawable(@DrawableRes colorRes: Int): Drawable? { - return ContextCompat.getDrawable(context, colorRes) + fun getDrawable(@DrawableRes drawableRes: Int): Drawable? { + return ContextCompat.getDrawable(context, drawableRes) } - fun getDrawable(@DrawableRes colorRes: Int, @ColorInt color: Int): Drawable? { - return ContextCompat.getDrawable(context, colorRes)?.let { + fun getDrawable(@DrawableRes drawableRes: Int, @ColorInt color: Int): Drawable? { + return ContextCompat.getDrawable(context, drawableRes)?.let { ThemeUtils.tintDrawableWithColor(it, color) } } diff --git a/vector/src/main/java/im/vector/app/features/form/FormAdvancedToggleItem.kt b/vector/src/main/java/im/vector/app/features/form/FormAdvancedToggleItem.kt new file mode 100644 index 0000000000..2d6535758e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/form/FormAdvancedToggleItem.kt @@ -0,0 +1,51 @@ +/* + * 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.form + +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.features.themes.ThemeUtils + +@EpoxyModelClass(layout = R.layout.item_form_advanced_toggle) +abstract class FormAdvancedToggleItem : VectorEpoxyModel() { + + @EpoxyAttribute lateinit var title: CharSequence + @EpoxyAttribute var expanded: Boolean = false + @EpoxyAttribute var listener: (() -> Unit)? = null + + override fun bind(holder: Holder) { + super.bind(holder) + val tintColor = ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary) + val expandedArrowDrawableRes = if (expanded) R.drawable.ic_expand_more_white else R.drawable.ic_expand_less_white + val expandedArrowDrawable = ContextCompat.getDrawable(holder.view.context, expandedArrowDrawableRes)?.also { + DrawableCompat.setTint(it, tintColor) + } + holder.titleView.setCompoundDrawablesWithIntrinsicBounds(null, null, expandedArrowDrawable, null) + holder.titleView.text = title + holder.view.setOnClickListener { listener?.invoke() } + } + + class Holder : VectorEpoxyHolder() { + val titleView by bind(R.id.itemFormAdvancedToggleTitleView) + } +} diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt index 4b3eacffaa..61799a741f 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt @@ -27,6 +27,9 @@ sealed class CreateRoomAction : VectorViewModelAction { data class SetIsInRoomDirectory(val isInRoomDirectory: Boolean) : CreateRoomAction() data class SetIsEncrypted(val isEncrypted: Boolean) : CreateRoomAction() + object ToggleShowAdvanced : CreateRoomAction() + data class DisableFederation(val disableFederation: Boolean) : CreateRoomAction() + object Create : CreateRoomAction() object Reset : CreateRoomAction() } 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 d1cc884336..157e192668 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 @@ -27,6 +27,7 @@ import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.resources.StringProvider import im.vector.app.features.discovery.settingsSectionTitleItem +import im.vector.app.features.form.formAdvancedToggleItem import im.vector.app.features.form.formEditTextItem import im.vector.app.features.form.formEditableAvatarItem import im.vector.app.features.form.formSubmitButtonItem @@ -148,6 +149,22 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin listener?.setIsEncrypted(value) } } + formAdvancedToggleItem { + id("showAdvanced") + title(stringProvider.getString(if (viewState.showAdvanced) R.string.hide_advanced else R.string.show_advanced)) + expanded(!viewState.showAdvanced) + listener { listener?.toggleShowAdvanced() } + } + if (viewState.showAdvanced) { + formSwitchItem { + id("federation") + enabled(enableFormElement) + title(stringProvider.getString(R.string.create_room_disable_federation_title, viewState.homeServerName)) + summary(stringProvider.getString(R.string.create_room_disable_federation_description)) + switchChecked(viewState.disableFederation) + listener { value -> listener?.setDisableFederation(value) } + } + } formSubmitButtonItem { id("submit") enabled(enableFormElement) @@ -165,6 +182,8 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin fun setIsInRoomDirectory(isInRoomDirectory: Boolean) fun setIsEncrypted(isEncrypted: Boolean) fun retry() + fun toggleShowAdvanced() + fun setDisableFederation(disableFederation: Boolean) fun submit() } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index 88b8a65a1c..729c97370c 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -110,6 +110,14 @@ class CreateRoomFragment @Inject constructor( viewModel.handle(CreateRoomAction.SetIsEncrypted(isEncrypted)) } + override fun toggleShowAdvanced() { + viewModel.handle(CreateRoomAction.ToggleShowAdvanced) + } + + override fun setDisableFederation(disableFederation: Boolean) { + viewModel.handle(CreateRoomAction.DisableFederation(disableFederation)) + } + override fun submit() { viewModel.handle(CreateRoomAction.Create) } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 57af95b107..fcb98916cc 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -53,9 +53,18 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr } init { + initHomeServerName() initAdminE2eByDefault() } + private fun initHomeServerName() { + setState { + copy( + homeServerName = session.myUserId.substringAfter(":") + ) + } + } + private var adminE2EByDefault = true private fun initAdminE2eByDefault() { @@ -99,9 +108,27 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr is CreateRoomAction.SetIsEncrypted -> setIsEncrypted(action) is CreateRoomAction.Create -> doCreateRoom() CreateRoomAction.Reset -> doReset() + CreateRoomAction.ToggleShowAdvanced -> toggleShowAdvanced() + is CreateRoomAction.DisableFederation -> disableFederation(action) }.exhaustive } + private fun disableFederation(action: CreateRoomAction.DisableFederation) { + setState { + copy(disableFederation = action.disableFederation) + } + } + + private fun toggleShowAdvanced() { + setState { + copy( + showAdvanced = !showAdvanced, + // Reset to false if advanced is hidden + disableFederation = disableFederation && !showAdvanced + ) + } + } + private fun doReset() { setState { // Delete temporary file with the avatar @@ -151,6 +178,8 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE // Public room preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT + // Disabling federation + disableFederation = state.disableFederation // Encryption if (state.isEncrypted) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt index 433cc02cc9..d1e5c0b1bd 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt @@ -28,6 +28,9 @@ data class CreateRoomViewState( val isPublic: Boolean = false, val isInRoomDirectory: Boolean = false, val isEncrypted: Boolean = false, + val showAdvanced: Boolean = false, + val disableFederation: Boolean = false, + val homeServerName: String = "", val hsAdminHasDisabledE2E: Boolean = false, val asyncCreateRoomRequest: Async = Uninitialized ) : MvRxState { diff --git a/vector/src/main/res/layout/item_form_advanced_toggle.xml b/vector/src/main/res/layout/item_form_advanced_toggle.xml new file mode 100644 index 0000000000..46609b64ca --- /dev/null +++ b/vector/src/main/res/layout/item_form_advanced_toggle.xml @@ -0,0 +1,34 @@ + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_form_switch.xml b/vector/src/main/res/layout/item_form_switch.xml index 24425a5eb4..cc662680bb 100644 --- a/vector/src/main/res/layout/item_form_switch.xml +++ b/vector/src/main/res/layout/item_form_switch.xml @@ -15,8 +15,6 @@ android:layout_marginStart="@dimen/layout_horizontal_margin" android:layout_marginEnd="@dimen/layout_horizontal_margin" android:duplicateParentState="true" - android:ellipsize="end" - android:maxLines="1" android:textColor="?riotx_text_primary" android:textSize="15sp" app:layout_constraintBottom_toTopOf="@+id/formSwitchSummary" diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 48729df815..5768750021 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2094,6 +2094,12 @@ "Enable encryption" "Once enabled, encryption cannot be disabled." + Show advanced + Hide advanced + + Block anyone not part of %s from ever joining this room + You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later. + Your email domain is not authorized to register on this server Untrusted sign in From af8b400bf4c61a9799d394e814d17c4e7b9ea16f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 13:44:55 +0100 Subject: [PATCH 02/10] Room creation form: input an alias for public room (#1314) --- .../session/room/failure/CreateRoomFailure.kt | 3 + .../session/room/create/CreateRoomTask.kt | 46 ++++++++-- .../app/features/form/FormSwitchItem.kt | 7 ++ .../createroom/CreateRoomAction.kt | 2 +- .../createroom/CreateRoomController.kt | 36 +++++--- .../createroom/CreateRoomFragment.kt | 5 +- .../createroom/CreateRoomViewModel.kt | 69 +++++++++----- .../createroom/CreateRoomViewState.kt | 8 +- .../createroom/RoomAliasEditItem.kt | 89 +++++++++++++++++++ .../res/layout/item_room_alias_text_input.xml | 63 +++++++++++++ vector/src/main/res/values/strings.xml | 5 ++ 11 files changed, 290 insertions(+), 43 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/roomdirectory/createroom/RoomAliasEditItem.kt create mode 100644 vector/src/main/res/layout/item_room_alias_text_input.xml diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt index b0df2963f7..88ab5e36c6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt @@ -22,4 +22,7 @@ import org.matrix.android.sdk.api.failure.MatrixError sealed class CreateRoomFailure : Failure.FeatureFailure() { object CreatedWithTimeout : CreateRoomFailure() data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure() + object RoomAliasEmpty: CreateRoomFailure() + object RoomAliasNotAvailable: CreateRoomFailure() + object RoomAliasInvalid: CreateRoomFailure() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt index 4f0aaf083d..8bf1f077b1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt @@ -31,8 +31,10 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI +import org.matrix.android.sdk.internal.session.room.alias.RoomAliasDescription import org.matrix.android.sdk.internal.session.room.read.SetReadMarkersTask import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask @@ -45,6 +47,7 @@ internal interface CreateRoomTask : Task internal class DefaultCreateRoomTask @Inject constructor( private val roomAPI: RoomAPI, + @UserId private val userId: String, @SessionDatabase private val monarchy: Monarchy, private val directChatsHelper: DirectChatsHelper, private val updateUserAccountDataTask: UpdateUserAccountDataTask, @@ -61,6 +64,31 @@ internal class DefaultCreateRoomTask @Inject constructor( ?: throw IllegalStateException("You can't create a direct room without an invitedUser") } else null + if (params.preset == CreateRoomPreset.PRESET_PUBLIC_CHAT) { + if (params.roomAliasName.isNullOrEmpty()) { + throw CreateRoomFailure.RoomAliasEmpty + } + // Check alias availability + val fullAlias = "#" + params.roomAliasName + ":" + userId.substringAfter(":") + try { + executeRequest(eventBus) { + apiCall = roomAPI.getRoomIdByAlias(fullAlias) + } + } catch (throwable: Throwable) { + if (throwable is Failure.ServerError && throwable.httpCode == 404) { + // This is a 404, so the alias is available: nominal case + null + } else { + // Other error, propagate it + throw throwable + } + } + ?.let { + // Alias already exists: error case + throw CreateRoomFailure.RoomAliasNotAvailable + } + } + val createRoomBody = createRoomBodyBuilder.build(params) val createRoomResponse = try { @@ -68,14 +96,18 @@ internal class DefaultCreateRoomTask @Inject constructor( apiCall = roomAPI.createRoom(createRoomBody) } } catch (throwable: Throwable) { - if (throwable is Failure.ServerError - && throwable.httpCode == 403 - && throwable.error.code == MatrixError.M_FORBIDDEN - && throwable.error.message.startsWith("Federation denied with")) { - throw CreateRoomFailure.CreatedWithFederationFailure(throwable.error) - } else { - throw throwable + if (throwable is Failure.ServerError) { + if (throwable.httpCode == 403 + && throwable.error.code == MatrixError.M_FORBIDDEN + && throwable.error.message.startsWith("Federation denied with")) { + throw CreateRoomFailure.CreatedWithFederationFailure(throwable.error) + } else if (throwable.httpCode == 400 + && throwable.error.code == MatrixError.M_UNKNOWN + && throwable.error.message == "Invalid characters in room alias") { + throw CreateRoomFailure.RoomAliasInvalid + } } + throw throwable } val roomId = createRoomResponse.roomId // Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before) diff --git a/vector/src/main/java/im/vector/app/features/form/FormSwitchItem.kt b/vector/src/main/java/im/vector/app/features/form/FormSwitchItem.kt index 08d1332920..0b274cccd8 100644 --- a/vector/src/main/java/im/vector/app/features/form/FormSwitchItem.kt +++ b/vector/src/main/java/im/vector/app/features/form/FormSwitchItem.kt @@ -16,7 +16,9 @@ package im.vector.app.features.form +import android.view.View import android.widget.TextView +import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import com.google.android.material.switchmaterial.SwitchMaterial @@ -43,6 +45,9 @@ abstract class FormSwitchItem : VectorEpoxyModel() { @EpoxyAttribute var summary: String? = null + @EpoxyAttribute + var showDivider: Boolean = true + override fun bind(holder: Holder) { super.bind(holder) holder.view.setOnClickListener { @@ -61,6 +66,7 @@ abstract class FormSwitchItem : VectorEpoxyModel() { holder.switchView.setOnCheckedChangeListener { _, isChecked -> listener?.invoke(isChecked) } + holder.divider.isVisible = showDivider } override fun shouldSaveViewState(): Boolean { @@ -77,5 +83,6 @@ abstract class FormSwitchItem : VectorEpoxyModel() { val titleView by bind(R.id.formSwitchTitle) val summaryView by bind(R.id.formSwitchSummary) val switchView by bind(R.id.formSwitchSwitch) + val divider by bind(R.id.formSwitchDivider) } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt index 61799a741f..b50c56e1db 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomAction.kt @@ -24,7 +24,7 @@ sealed class CreateRoomAction : VectorViewModelAction { data class SetName(val name: String) : CreateRoomAction() data class SetTopic(val topic: String) : CreateRoomAction() data class SetIsPublic(val isPublic: Boolean) : CreateRoomAction() - data class SetIsInRoomDirectory(val isInRoomDirectory: Boolean) : CreateRoomAction() + data class SetRoomAliasLocalPart(val aliasLocalPart: String) : CreateRoomAction() data class SetIsEncrypted(val isEncrypted: Boolean) : CreateRoomAction() object ToggleShowAdvanced : CreateRoomAction() 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 157e192668..3f86d1adca 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 @@ -32,6 +32,7 @@ import im.vector.app.features.form.formEditTextItem import im.vector.app.features.form.formEditableAvatarItem import im.vector.app.features.form.formSubmitButtonItem import im.vector.app.features.form.formSwitchItem +import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure import javax.inject.Inject class CreateRoomController @Inject constructor(private val stringProvider: StringProvider, @@ -61,6 +62,7 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin is Fail -> { // display the form buildForm(viewState, true) + // TODO BMA DO NOT COMMIT Update this errorWithRetryItem { id("error") text(errorFormatter.toHumanReadable(asyncCreateRoom.error)) @@ -115,21 +117,32 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin enabled(enableFormElement) title(stringProvider.getString(R.string.create_room_public_title)) summary(stringProvider.getString(R.string.create_room_public_description)) - switchChecked(viewState.isPublic) + switchChecked(viewState.roomType is CreateRoomViewState.RoomType.Public) + showDivider(viewState.roomType !is CreateRoomViewState.RoomType.Public) listener { value -> listener?.setIsPublic(value) } } - formSwitchItem { - id("directory") - enabled(enableFormElement) - title(stringProvider.getString(R.string.create_room_directory_title)) - summary(stringProvider.getString(R.string.create_room_directory_description)) - switchChecked(viewState.isInRoomDirectory) - - listener { value -> - listener?.setIsInRoomDirectory(value) + // Room alias + if (viewState.roomType is CreateRoomViewState.RoomType.Public) { + roomAliasEditItem { + id("alias") + enabled(enableFormElement) + value(viewState.roomType.aliasLocalPart) + homeServer(":" + viewState.homeServerName) + errorMessage( + when ((viewState.asyncCreateRoomRequest as? Fail)?.error) { + is CreateRoomFailure.RoomAliasEmpty -> R.string.create_room_alias_empty + is CreateRoomFailure.RoomAliasNotAvailable -> R.string.create_room_alias_already_in_use + is CreateRoomFailure.RoomAliasInvalid -> R.string.create_room_alias_invalid + else -> null + } + ?.let { stringProvider.getString(it) } + ) + onTextChange { value -> + listener?.setAliasLocalPart(value) + } } } formSwitchItem { @@ -162,6 +175,7 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin title(stringProvider.getString(R.string.create_room_disable_federation_title, viewState.homeServerName)) summary(stringProvider.getString(R.string.create_room_disable_federation_description)) switchChecked(viewState.disableFederation) + showDivider(false) listener { value -> listener?.setDisableFederation(value) } } } @@ -179,7 +193,7 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin fun onNameChange(newName: String) fun onTopicChange(newTopic: String) fun setIsPublic(isPublic: Boolean) - fun setIsInRoomDirectory(isInRoomDirectory: Boolean) + fun setAliasLocalPart(aliasLocalPart: String) fun setIsEncrypted(isEncrypted: Boolean) fun retry() fun toggleShowAdvanced() diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index 729c97370c..124b6a415a 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -46,6 +46,7 @@ class CreateRoomFragment @Inject constructor( OnBackPressed { private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel + // TODO BMA: use fragmentViewMode(). Else back does not reset the form. Use Fragment Argument to pass room name private val viewModel: CreateRoomViewModel by activityViewModel() private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) @@ -102,8 +103,8 @@ class CreateRoomFragment @Inject constructor( viewModel.handle(CreateRoomAction.SetIsPublic(isPublic)) } - override fun setIsInRoomDirectory(isInRoomDirectory: Boolean) { - viewModel.handle(CreateRoomAction.SetIsInRoomDirectory(isInRoomDirectory)) + override fun setAliasLocalPart(aliasLocalPart: String) { + viewModel.handle(CreateRoomAction.SetRoomAliasLocalPart(aliasLocalPart)) } override fun setIsEncrypted(isEncrypted: Boolean) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index fcb98916cc..52e1b3f801 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -77,7 +77,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr setState { copy( - isEncrypted = !isPublic && adminE2EByDefault, + isEncrypted = roomType is CreateRoomViewState.RoomType.Private && adminE2EByDefault, hsAdminHasDisabledE2E = !adminE2EByDefault ) } @@ -100,16 +100,16 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr override fun handle(action: CreateRoomAction) { when (action) { - is CreateRoomAction.SetAvatar -> setAvatar(action) - is CreateRoomAction.SetName -> setName(action) - is CreateRoomAction.SetTopic -> setTopic(action) - is CreateRoomAction.SetIsPublic -> setIsPublic(action) - is CreateRoomAction.SetIsInRoomDirectory -> setIsInRoomDirectory(action) - is CreateRoomAction.SetIsEncrypted -> setIsEncrypted(action) - is CreateRoomAction.Create -> doCreateRoom() - CreateRoomAction.Reset -> doReset() - CreateRoomAction.ToggleShowAdvanced -> toggleShowAdvanced() - is CreateRoomAction.DisableFederation -> disableFederation(action) + is CreateRoomAction.SetAvatar -> setAvatar(action) + is CreateRoomAction.SetName -> setName(action) + is CreateRoomAction.SetTopic -> setTopic(action) + is CreateRoomAction.SetIsPublic -> setIsPublic(action) + is CreateRoomAction.SetRoomAliasLocalPart -> setRoomAliasLocalPart(action) + is CreateRoomAction.SetIsEncrypted -> setIsEncrypted(action) + is CreateRoomAction.Create -> doCreateRoom() + CreateRoomAction.Reset -> doReset() + CreateRoomAction.ToggleShowAdvanced -> toggleShowAdvanced() + is CreateRoomAction.DisableFederation -> disableFederation(action) }.exhaustive } @@ -150,13 +150,31 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr private fun setTopic(action: CreateRoomAction.SetTopic) = setState { copy(roomTopic = action.topic) } private fun setIsPublic(action: CreateRoomAction.SetIsPublic) = setState { - copy( - isPublic = action.isPublic, - isEncrypted = !action.isPublic && adminE2EByDefault - ) + if (action.isPublic) { + copy( + roomType = CreateRoomViewState.RoomType.Public(""), + isEncrypted = false + ) + } else { + copy( + roomType = CreateRoomViewState.RoomType.Private, + isEncrypted = adminE2EByDefault + ) + } } - private fun setIsInRoomDirectory(action: CreateRoomAction.SetIsInRoomDirectory) = setState { copy(isInRoomDirectory = action.isInRoomDirectory) } + private fun setRoomAliasLocalPart(action: CreateRoomAction.SetRoomAliasLocalPart) { + withState { state -> + if (state.roomType is CreateRoomViewState.RoomType.Public) { + setState { + copy( + roomType = CreateRoomViewState.RoomType.Public(action.aliasLocalPart) + ) + } + } + } + // Else ignore + } private fun setIsEncrypted(action: CreateRoomAction.SetIsEncrypted) = setState { copy(isEncrypted = action.isEncrypted) } @@ -174,10 +192,21 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr name = state.roomName.takeIf { it.isNotBlank() } topic = state.roomTopic.takeIf { it.isNotBlank() } avatarUri = state.avatarUri - // Directory visibility - visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE - // Public room - preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT + when (state.roomType) { + is CreateRoomViewState.RoomType.Public -> { + // Directory visibility + visibility = RoomDirectoryVisibility.PUBLIC + // Preset + preset = CreateRoomPreset.PRESET_PUBLIC_CHAT + roomAliasName = state.roomType.aliasLocalPart + } + is CreateRoomViewState.RoomType.Private -> { + // Directory visibility + visibility = RoomDirectoryVisibility.PRIVATE + // Preset + preset = CreateRoomPreset.PRESET_PRIVATE_CHAT + } + }.exhaustive // Disabling federation disableFederation = state.disableFederation diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt index d1e5c0b1bd..cc7a441eb5 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt @@ -25,8 +25,7 @@ data class CreateRoomViewState( val avatarUri: Uri? = null, val roomName: String = "", val roomTopic: String = "", - val isPublic: Boolean = false, - val isInRoomDirectory: Boolean = false, + val roomType: RoomType = RoomType.Private, val isEncrypted: Boolean = false, val showAdvanced: Boolean = false, val disableFederation: Boolean = false, @@ -39,4 +38,9 @@ data class CreateRoomViewState( * Return true if there is not important input from user */ fun isEmpty() = avatarUri == null && roomName.isEmpty() && roomTopic.isEmpty() + + sealed class RoomType { + object Private : RoomType() + data class Public(val aliasLocalPart: String) : RoomType() + } } 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 new file mode 100644 index 0000000000..041a5c5c51 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/RoomAliasEditItem.kt @@ -0,0 +1,89 @@ +/* + * 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.view.View +import android.widget.TextView +import androidx.core.view.isVisible +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.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.platform.SimpleTextWatcher + +@EpoxyModelClass(layout = R.layout.item_room_alias_text_input) +abstract class RoomAliasEditItem : VectorEpoxyModel() { + + @EpoxyAttribute + var value: String? = null + + @EpoxyAttribute + var showBottomSeparator: Boolean = true + + @EpoxyAttribute + var errorMessage: String? = null + + @EpoxyAttribute + var homeServer: String? = null + + @EpoxyAttribute + var enabled: Boolean = true + + @EpoxyAttribute + var onTextChange: ((String) -> Unit)? = 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 + + // Update only if text is different and value is not null + if (value != null && holder.textInputEditText.text.toString() != value) { + holder.textInputEditText.setText(value) + } + holder.textInputEditText.isEnabled = enabled + holder.textInputEditText.addTextChangedListener(onTextChangeListener) + holder.homeServerText.text = homeServer + holder.bottomSeparator.isVisible = showBottomSeparator + } + + 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(R.id.itemRoomAliasTextInputLayout) + val textInputEditText by bind(R.id.itemRoomAliasTextInputEditText) + val homeServerText by bind(R.id.itemRoomAliasHomeServer) + val bottomSeparator by bind(R.id.itemRoomAliasDivider) + } +} 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 new file mode 100644 index 0000000000..44c76b631d --- /dev/null +++ b/vector/src/main/res/layout/item_room_alias_text_input.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 5768750021..ee8c3f7da8 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2100,6 +2100,11 @@ Block anyone not part of %s from ever joining this room 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 + This address is already in use + Please provide a room address + Some characters are not allowed + Your email domain is not authorized to register on this server Untrusted sign in From 16b6678aa2df443efe95aeaddb572893a99567c9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 14:14:43 +0100 Subject: [PATCH 03/10] CreateRoomFragment: use argument instead of Activity ViewModel to pass the initial room name --- .../roomdirectory/RoomDirectoryActivity.kt | 14 +++++++------- .../createroom/CreateRoomActivity.kt | 12 +++++------- .../createroom/CreateRoomFragment.kt | 15 ++++++++++++--- .../createroom/CreateRoomViewModel.kt | 12 +++--------- .../createroom/CreateRoomViewState.kt | 4 ++++ 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt index 9dc41cbc21..a21f4e670a 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt @@ -26,18 +26,15 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.platform.VectorBaseActivity -import im.vector.app.features.roomdirectory.createroom.CreateRoomAction import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment -import im.vector.app.features.roomdirectory.createroom.CreateRoomViewModel +import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerFragment import javax.inject.Inject class RoomDirectoryActivity : VectorBaseActivity() { - @Inject lateinit var createRoomViewModelFactory: CreateRoomViewModel.Factory @Inject lateinit var roomDirectoryViewModelFactory: RoomDirectoryViewModel.Factory private val roomDirectoryViewModel: RoomDirectoryViewModel by viewModel() - private val createRoomViewModel: CreateRoomViewModel by viewModel() private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel override fun getLayoutRes() = R.layout.activity_simple @@ -60,10 +57,13 @@ class RoomDirectoryActivity : VectorBaseActivity() { when (sharedAction) { is RoomDirectorySharedAction.Back -> onBackPressed() is RoomDirectorySharedAction.CreateRoom -> { - addFragmentToBackstack(R.id.simpleFragmentContainer, CreateRoomFragment::class.java) - // Transmit the filter to the createRoomViewModel + // Transmit the filter to the CreateRoomFragment withState(roomDirectoryViewModel) { - createRoomViewModel.handle(CreateRoomAction.SetName(it.currentFilter)) + addFragmentToBackstack( + R.id.simpleFragmentContainer, + CreateRoomFragment::class.java, + CreateRoomArgs(it.currentFilter) + ) } } is RoomDirectorySharedAction.ChangeProtocol -> diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt index e003c4905c..b6ee00a52f 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -20,7 +20,6 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.widget.Toolbar -import com.airbnb.mvrx.viewModel import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment @@ -28,16 +27,12 @@ import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel -import javax.inject.Inject /** * Simple container for [CreateRoomFragment] */ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { - @Inject lateinit var createRoomViewModelFactory: CreateRoomViewModel.Factory - private val createRoomViewModel: CreateRoomViewModel by viewModel() - private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel override fun getLayoutRes() = R.layout.activity_simple @@ -52,8 +47,11 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { override fun initUiAndData() { if (isFirstCreation()) { - addFragment(R.id.simpleFragmentContainer, CreateRoomFragment::class.java) - createRoomViewModel.handle(CreateRoomAction.SetName(intent?.getStringExtra(INITIAL_NAME) ?: "")) + addFragment( + R.id.simpleFragmentContainer, + CreateRoomFragment::class.java, + CreateRoomArgs(intent?.getStringExtra(INITIAL_NAME) ?: "") + ) } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index 124b6a415a..a20bc7dbf5 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -18,10 +18,12 @@ package im.vector.app.features.roomdirectory.createroom import android.net.Uri import android.os.Bundle +import android.os.Parcelable import android.view.View import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.Success -import com.airbnb.mvrx.activityViewModel +import com.airbnb.mvrx.args +import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper @@ -33,12 +35,19 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel +import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_create_room.* import timber.log.Timber import javax.inject.Inject +@Parcelize +data class CreateRoomArgs( + val initialName: String +) : Parcelable + class CreateRoomFragment @Inject constructor( private val createRoomController: CreateRoomController, + val createRoomViewModelFactory: CreateRoomViewModel.Factory, colorProvider: ColorProvider ) : VectorBaseFragment(), CreateRoomController.Listener, @@ -46,8 +55,8 @@ class CreateRoomFragment @Inject constructor( OnBackPressed { private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel - // TODO BMA: use fragmentViewMode(). Else back does not reset the form. Use Fragment Argument to pass room name - private val viewModel: CreateRoomViewModel by activityViewModel() + private val viewModel: CreateRoomViewModel by fragmentViewModel() + private val args: CreateRoomArgs by args() private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 52e1b3f801..e25298b0f1 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -17,10 +17,9 @@ package im.vector.app.features.roomdirectory.createroom import androidx.core.net.toFile -import androidx.fragment.app.FragmentActivity import androidx.lifecycle.viewModelScope -import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success @@ -31,7 +30,6 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isE2EByDefault -import im.vector.app.features.roomdirectory.RoomDirectoryActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback @@ -88,13 +86,9 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr @JvmStatic override fun create(viewModelContext: ViewModelContext, state: CreateRoomViewState): CreateRoomViewModel? { - val activity: FragmentActivity = (viewModelContext as ActivityViewModelContext).activity() + val fragment: CreateRoomFragment = (viewModelContext as FragmentViewModelContext).fragment() - return when (activity) { - is CreateRoomActivity -> activity.createRoomViewModelFactory.create(state) - is RoomDirectoryActivity -> activity.createRoomViewModelFactory.create(state) - else -> error("Wrong activity") - } + return fragment.createRoomViewModelFactory.create(state) } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt index cc7a441eb5..398f804db3 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt @@ -34,6 +34,10 @@ data class CreateRoomViewState( val asyncCreateRoomRequest: Async = Uninitialized ) : MvRxState { + constructor(args: CreateRoomArgs) : this( + roomName = args.initialName + ) + /** * Return true if there is not important input from user */ From 507d5d37588611ccf6690ff616bcf5024a417ee1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 14:21:53 +0100 Subject: [PATCH 04/10] Warn the user if room alias is not empty and he wants to leave the form. --- .../roomdirectory/createroom/CreateRoomViewState.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt index 398f804db3..4609693c8f 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt @@ -20,6 +20,7 @@ import android.net.Uri import com.airbnb.mvrx.Async import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized +import org.matrix.android.sdk.api.extensions.orTrue data class CreateRoomViewState( val avatarUri: Uri? = null, @@ -41,7 +42,10 @@ data class CreateRoomViewState( /** * Return true if there is not important input from user */ - fun isEmpty() = avatarUri == null && roomName.isEmpty() && roomTopic.isEmpty() + fun isEmpty() = avatarUri == null + && roomName.isEmpty() + && roomTopic.isEmpty() + && (roomType as? RoomType.Public)?.aliasLocalPart?.isEmpty().orTrue() sealed class RoomType { object Private : RoomType() From 514263ae122a67a5ce7d6078a8d816db7eac3320 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 14:51:10 +0100 Subject: [PATCH 05/10] Room creation Fragment: no more "Retry" action, loading and error displayed in a dialog --- .../session/room/failure/CreateRoomFailure.kt | 8 ++-- .../session/room/create/CreateRoomTask.kt | 6 +-- .../createroom/CreateRoomController.kt | 37 +++---------------- .../createroom/CreateRoomFragment.kt | 27 ++++++++++---- .../createroom/CreateRoomViewEvents.kt | 1 + .../createroom/CreateRoomViewModel.kt | 2 + .../main/res/layout/fragment_create_room.xml | 2 + vector/src/main/res/values/strings.xml | 1 + 8 files changed, 40 insertions(+), 44 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt index 88ab5e36c6..b4e2dc645c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt @@ -22,7 +22,9 @@ import org.matrix.android.sdk.api.failure.MatrixError sealed class CreateRoomFailure : Failure.FeatureFailure() { object CreatedWithTimeout : CreateRoomFailure() data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure() - object RoomAliasEmpty: CreateRoomFailure() - object RoomAliasNotAvailable: CreateRoomFailure() - object RoomAliasInvalid: CreateRoomFailure() + sealed class RoomAliasError : CreateRoomFailure() { + object AliasEmpty : RoomAliasError() + object AliasNotAvailable : RoomAliasError() + object AliasInvalid : RoomAliasError() + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt index 8bf1f077b1..0fe9b0ba68 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt @@ -66,7 +66,7 @@ internal class DefaultCreateRoomTask @Inject constructor( if (params.preset == CreateRoomPreset.PRESET_PUBLIC_CHAT) { if (params.roomAliasName.isNullOrEmpty()) { - throw CreateRoomFailure.RoomAliasEmpty + throw CreateRoomFailure.RoomAliasError.AliasEmpty } // Check alias availability val fullAlias = "#" + params.roomAliasName + ":" + userId.substringAfter(":") @@ -85,7 +85,7 @@ internal class DefaultCreateRoomTask @Inject constructor( } ?.let { // Alias already exists: error case - throw CreateRoomFailure.RoomAliasNotAvailable + throw CreateRoomFailure.RoomAliasError.AliasNotAvailable } } @@ -104,7 +104,7 @@ internal class DefaultCreateRoomTask @Inject constructor( } else if (throwable.httpCode == 400 && throwable.error.code == MatrixError.M_UNKNOWN && throwable.error.message == "Invalid characters in room alias") { - throw CreateRoomFailure.RoomAliasInvalid + throw CreateRoomFailure.RoomAliasError.AliasInvalid } } throw throwable 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 3f86d1adca..7acc2d1490 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 @@ -44,32 +44,8 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin var index = 0 override fun buildModels(viewState: CreateRoomViewState) { - when (val asyncCreateRoom = viewState.asyncCreateRoomRequest) { - is Success -> { - // Nothing to display, the screen will be closed - } - is Loading -> { - // display the form - buildForm(viewState, false) - loadingItem { - id("loading") - } - } - is Uninitialized -> { - // display the form - buildForm(viewState, true) - } - is Fail -> { - // display the form - buildForm(viewState, true) - // TODO BMA DO NOT COMMIT Update this - errorWithRetryItem { - id("error") - text(errorFormatter.toHumanReadable(asyncCreateRoom.error)) - listener { listener?.retry() } - } - } - } + // display the form + buildForm(viewState, viewState.asyncCreateRoomRequest !is Loading) } private fun buildForm(viewState: CreateRoomViewState, enableFormElement: Boolean) { @@ -133,10 +109,10 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin homeServer(":" + viewState.homeServerName) errorMessage( when ((viewState.asyncCreateRoomRequest as? Fail)?.error) { - is CreateRoomFailure.RoomAliasEmpty -> R.string.create_room_alias_empty - is CreateRoomFailure.RoomAliasNotAvailable -> R.string.create_room_alias_already_in_use - is CreateRoomFailure.RoomAliasInvalid -> R.string.create_room_alias_invalid - else -> null + is CreateRoomFailure.RoomAliasError.AliasEmpty -> R.string.create_room_alias_empty + is CreateRoomFailure.RoomAliasError.AliasNotAvailable -> R.string.create_room_alias_already_in_use + is CreateRoomFailure.RoomAliasError.AliasInvalid -> R.string.create_room_alias_invalid + else -> null } ?.let { stringProvider.getString(it) } ) @@ -195,7 +171,6 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin fun setIsPublic(isPublic: Boolean) fun setAliasLocalPart(aliasLocalPart: String) fun setIsEncrypted(isEncrypted: Boolean) - fun retry() fun toggleShowAdvanced() fun setDisableFederation(disableFederation: Boolean) fun submit() diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index a20bc7dbf5..fb90752764 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -21,6 +21,8 @@ import android.os.Bundle import android.os.Parcelable import android.view.View import androidx.appcompat.app.AlertDialog +import androidx.core.view.isVisible +import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel @@ -37,7 +39,8 @@ import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_create_room.* -import timber.log.Timber +import kotlinx.android.synthetic.main.merge_overlay_waiting_view.* +import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure import javax.inject.Inject @Parcelize @@ -66,17 +69,31 @@ class CreateRoomFragment @Inject constructor( super.onViewCreated(view, savedInstanceState) vectorBaseActivity.setSupportActionBar(createRoomToolbar) sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java) + setupWaitingView() setupRecyclerView() createRoomClose.debouncedClicks { sharedActionViewModel.post(RoomDirectorySharedAction.Back) } viewModel.observeViewEvents { when (it) { - CreateRoomViewEvents.Quit -> vectorBaseActivity.onBackPressed() + CreateRoomViewEvents.Quit -> vectorBaseActivity.onBackPressed() + is CreateRoomViewEvents.Failure -> showFailure(it.throwable) }.exhaustive } } + override fun showFailure(throwable: Throwable) { + // Note: RoomAliasError are displayed directly in the form + if (throwable !is CreateRoomFailure.RoomAliasError) { + super.showFailure(throwable) + } + } + + private fun setupWaitingView() { + waiting_view_status_text.isVisible = true + waiting_view_status_text.setText(R.string.create_room_in_progress) + } + override fun onDestroyView() { createRoomForm.cleanup() createRoomController.listener = null @@ -132,11 +149,6 @@ class CreateRoomFragment @Inject constructor( viewModel.handle(CreateRoomAction.Create) } - override fun retry() { - Timber.v("Retry") - viewModel.handle(CreateRoomAction.Create) - } - override fun onBackPressed(toolbarButton: Boolean): Boolean { return withState(viewModel) { return@withState if (!it.isEmpty()) { @@ -157,6 +169,7 @@ class CreateRoomFragment @Inject constructor( override fun invalidate() = withState(viewModel) { state -> val async = state.asyncCreateRoomRequest + waiting_view.isVisible = async is Loading if (async is Success) { // Navigate to freshly created room navigator.openRoom(requireActivity(), async()) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewEvents.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewEvents.kt index 4ff4ee4bdf..af745ce5ff 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewEvents.kt @@ -22,5 +22,6 @@ import im.vector.app.core.platform.VectorViewEvents * Transient events for room creation screen */ sealed class CreateRoomViewEvents : VectorViewEvents { + data class Failure(val throwable: Throwable) : CreateRoomViewEvents() object Quit : CreateRoomViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index e25298b0f1..4cffbf68dd 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -36,6 +36,7 @@ import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session +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.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset @@ -221,6 +222,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr setState { copy(asyncCreateRoomRequest = Fail(failure)) } + _viewEvents.post(CreateRoomViewEvents.Failure(failure)) } }) } diff --git a/vector/src/main/res/layout/fragment_create_room.xml b/vector/src/main/res/layout/fragment_create_room.xml index 0fe5caa968..3abcafc94d 100644 --- a/vector/src/main/res/layout/fragment_create_room.xml +++ b/vector/src/main/res/layout/fragment_create_room.xml @@ -67,5 +67,7 @@ + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index ee8c3f7da8..f00e51710d 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2104,6 +2104,7 @@ This address is already in use Please provide a room address Some characters are not allowed + Creating room… Your email domain is not authorized to register on this server From f6aee3d64e372c751a0ca16291890924275f758b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 14:54:01 +0100 Subject: [PATCH 06/10] Cleanup --- .../features/roomdirectory/createroom/CreateRoomController.kt | 4 ---- .../features/roomdirectory/createroom/CreateRoomViewModel.kt | 1 - 2 files changed, 5 deletions(-) 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 7acc2d1490..740e73b955 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 @@ -19,11 +19,7 @@ package im.vector.app.features.roomdirectory.createroom import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized import im.vector.app.R -import im.vector.app.core.epoxy.errorWithRetryItem -import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.resources.StringProvider import im.vector.app.features.discovery.settingsSectionTitleItem diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 4cffbf68dd..8478b0f3b8 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -36,7 +36,6 @@ import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.api.session.Session -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.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset From 0c7f4c2af572188f7f9ddcbc050c8dea178a8d7d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 15:13:43 +0100 Subject: [PATCH 07/10] Reset error in the form --- .../roomdirectory/createroom/CreateRoomViewModel.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 8478b0f3b8..216a016fbe 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -23,6 +23,7 @@ import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject @@ -147,6 +148,8 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr if (action.isPublic) { copy( roomType = CreateRoomViewState.RoomType.Public(""), + // Reset any error in the form about alias + asyncCreateRoomRequest = Uninitialized, isEncrypted = false ) } else { @@ -162,7 +165,9 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr if (state.roomType is CreateRoomViewState.RoomType.Public) { setState { copy( - roomType = CreateRoomViewState.RoomType.Public(action.aliasLocalPart) + roomType = CreateRoomViewState.RoomType.Public(action.aliasLocalPart), + // Reset any error in the form about alias + asyncCreateRoomRequest = Uninitialized ) } } From 702d21fbc38fcad79f09b4d0cb2bd7a27edbf207 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 15:27:59 +0100 Subject: [PATCH 08/10] No encryption for public room (#1314) --- .../createroom/CreateRoomController.kt | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) 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 740e73b955..235fddf9d4 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 @@ -116,22 +116,23 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin listener?.setAliasLocalPart(value) } } - } - formSwitchItem { - id("encryption") - enabled(enableFormElement) - title(stringProvider.getString(R.string.create_room_encryption_title)) - summary( - if (viewState.hsAdminHasDisabledE2E) { - stringProvider.getString(R.string.settings_hs_admin_e2e_disabled) - } else { - stringProvider.getString(R.string.create_room_encryption_description) - } - ) - switchChecked(viewState.isEncrypted) + } else { + formSwitchItem { + id("encryption") + enabled(enableFormElement) + title(stringProvider.getString(R.string.create_room_encryption_title)) + summary( + if (viewState.hsAdminHasDisabledE2E) { + stringProvider.getString(R.string.settings_hs_admin_e2e_disabled) + } else { + stringProvider.getString(R.string.create_room_encryption_description) + } + ) + switchChecked(viewState.isEncrypted) - listener { value -> - listener?.setIsEncrypted(value) + listener { value -> + listener?.setIsEncrypted(value) + } } } formAdvancedToggleItem { From 57d55e05e745117c3bc45ac1adba5437f29324cc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 18 Nov 2020 15:36:05 +0100 Subject: [PATCH 09/10] Update comment --- .../features/roomdirectory/createroom/CreateRoomController.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 235fddf9d4..aaf7b6ead5 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 @@ -96,8 +96,8 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin listener?.setIsPublic(value) } } - // Room alias if (viewState.roomType is CreateRoomViewState.RoomType.Public) { + // Room alias for public room roomAliasEditItem { id("alias") enabled(enableFormElement) @@ -117,6 +117,7 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin } } } else { + // Room encryption for private room formSwitchItem { id("encryption") enabled(enableFormElement) From c50c028c9eb2e871c6de8829d9d1dfac29953023 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 19 Nov 2020 15:22:24 +0100 Subject: [PATCH 10/10] Code quality --- vector/src/main/res/layout/item_room_alias_text_input.xml | 5 ++--- vector/src/main/res/values/donottranslate.xml | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) 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 index 44c76b631d..9216fc6b7e 100644 --- a/vector/src/main/res/layout/item_room_alias_text_input.xml +++ b/vector/src/main/res/layout/item_room_alias_text_input.xml @@ -12,11 +12,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/layout_horizontal_margin" - android:text="#" + android:text="@string/matrix_room_alias_prefix" android:textSize="18sp" app:layout_constraintBaseline_toBaselineOf="@+id/itemRoomAliasTextInputLayout" - app:layout_constraintStart_toStartOf="parent" - tools:ignore="HardcodedText" /> + app:layout_constraintStart_toStartOf="parent" /> ******** + # + Not implemented yet in Element