mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 13:38:49 +03:00
Room creation form: input an alias for public room (#1314)
This commit is contained in:
parent
579efb016a
commit
af8b400bf4
11 changed files with 290 additions and 43 deletions
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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<CreateRoomParams, String>
|
|||
|
||||
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<RoomAliasDescription>(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)
|
||||
|
|
|
@ -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<FormSwitchItem.Holder>() {
|
|||
@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<FormSwitchItem.Holder>() {
|
|||
holder.switchView.setOnCheckedChangeListener { _, isChecked ->
|
||||
listener?.invoke(isChecked)
|
||||
}
|
||||
holder.divider.isVisible = showDivider
|
||||
}
|
||||
|
||||
override fun shouldSaveViewState(): Boolean {
|
||||
|
@ -77,5 +83,6 @@ abstract class FormSwitchItem : VectorEpoxyModel<FormSwitchItem.Holder>() {
|
|||
val titleView by bind<TextView>(R.id.formSwitchTitle)
|
||||
val summaryView by bind<TextView>(R.id.formSwitchSummary)
|
||||
val switchView by bind<SwitchMaterial>(R.id.formSwitchSwitch)
|
||||
val divider by bind<View>(R.id.formSwitchDivider)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<RoomAliasEditItem.Holder>() {
|
||||
|
||||
@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<TextInputLayout>(R.id.itemRoomAliasTextInputLayout)
|
||||
val textInputEditText by bind<TextInputEditText>(R.id.itemRoomAliasTextInputEditText)
|
||||
val homeServerText by bind<TextView>(R.id.itemRoomAliasHomeServer)
|
||||
val bottomSeparator by bind<View>(R.id.itemRoomAliasDivider)
|
||||
}
|
||||
}
|
63
vector/src/main/res/layout/item_room_alias_text_input.xml
Normal file
63
vector/src/main/res/layout/item_room_alias_text_input.xml
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:minHeight="@dimen/item_form_min_height">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemRoomAliasHash"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:text="#"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/itemRoomAliasTextInputLayout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/itemRoomAliasTextInputLayout"
|
||||
style="@style/VectorTextInputLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:errorEnabled="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/itemRoomAliasDivider"
|
||||
app:layout_constraintEnd_toStartOf="@+id/itemRoomAliasHomeServer"
|
||||
app:layout_constraintStart_toEndOf="@+id/itemRoomAliasHash"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/itemRoomAliasTextInputEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/create_room_alias_hint"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemRoomAliasHomeServer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:maxWidth="200dp"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/itemRoomAliasTextInputLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:text=":matrix.org" />
|
||||
|
||||
<View
|
||||
android:id="@+id/itemRoomAliasDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="?riotx_header_panel_border_mobile"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -2100,6 +2100,11 @@
|
|||
<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="create_room_alias_hint">Room address</string>
|
||||
<string name="create_room_alias_already_in_use">This address is already in use</string>
|
||||
<string name="create_room_alias_empty">Please provide a room address</string>
|
||||
<string name="create_room_alias_invalid">Some characters are not allowed</string>
|
||||
|
||||
<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>
|
||||
|
|
Loading…
Reference in a new issue