Room creation form: add advanced section to disable federation (#1314)

This commit is contained in:
Benoit Marty 2020-11-16 17:25:42 +01:00
parent 2b1b9d35a2
commit 579efb016a
14 changed files with 181 additions and 10 deletions

View file

@ -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)

View file

@ -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"
}
}

View file

@ -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")

View file

@ -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,

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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()
}

View file

@ -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()
}
}

View file

@ -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)
}

View file

@ -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) {

View file

@ -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 {

View file

@ -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>

View file

@ -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"

View file

@ -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>