From 579efb016ae0e1873ac575252d59ab9afc7f1cad Mon Sep 17 00:00:00 2001 From: Benoit Marty <benoit@matrix.org> Date: Mon, 16 Nov 2020 17:25:42 +0100 Subject: [PATCH] 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<String, Any>() + + /** + * 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<ThreePidInviteBody>?, /** - * 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<FormAdvancedToggleItem.Holder>() { + + @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<TextView>(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<String> = 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/itemFormAdvancedToggleRootView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?riotx_background" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingStart="@dimen/layout_horizontal_margin" + android:paddingTop="12dp" + android:paddingEnd="@dimen/layout_horizontal_margin" + android:paddingBottom="12dp"> + + <TextView + android:id="@+id/itemFormAdvancedToggleTitleView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:ellipsize="end" + android:gravity="center_vertical" + android:maxLines="1" + android:textColor="?riotx_text_secondary" + android:textSize="14sp" + android:textStyle="bold" + app:drawableTint="?riotx_text_secondary" + tools:drawableEnd="@drawable/ic_expand_more_white" + tools:text="@string/show_advanced" /> + +</LinearLayout> \ 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 @@ <string name="create_room_encryption_title">"Enable encryption"</string> <string name="create_room_encryption_description">"Once enabled, encryption cannot be disabled."</string> + <string name="show_advanced">Show advanced</string> + <string name="hide_advanced">Hide advanced</string> + + <string name="create_room_disable_federation_title">Block anyone not part of %s from ever joining this room</string> + <string name="create_room_disable_federation_description">You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.</string> + <string name="login_error_threepid_denied">Your email domain is not authorized to register on this server</string> <string name="verification_conclusion_warning">Untrusted sign in</string>