Create room screen - WIP TODO: screen rotation - navigate to created room

This commit is contained in:
Benoit Marty 2019-06-07 16:07:35 +02:00
parent ed18a504e4
commit 4c5bffe0f5
18 changed files with 698 additions and 9 deletions

View file

@ -100,7 +100,7 @@ class CreateRoomParams {
* private_chat => join_rules is set to invite. history_visibility is set to shared. * private_chat => join_rules is set to invite. history_visibility is set to shared.
* trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the * trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the
* room creator. * room creator.
* public_chat: => join_rules is set to public. history_visibility is set to shared. One of: ["private_chat", "public_chat", "trusted_private_chat"] * public_chat: => join_rules is set to public. history_visibility is set to shared.
*/ */
var preset: CreateRoomPreset? = null var preset: CreateRoomPreset? = null

View file

@ -54,6 +54,7 @@ internal class DefaultCreateRoomTask(private val roomAPI: RoomAPI,
handlerThread.start() handlerThread.start()
val handler = Handler(handlerThread.looper) val handler = Handler(handlerThread.looper)
// TODO Maybe do the same code for join room request ?
handler.post { handler.post {
val realm = Realm.getInstance(realmConfiguration) val realm = Realm.getInstance(realmConfiguration)

View file

@ -0,0 +1,77 @@
/*
* 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.riotredesign.features.form
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.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.core.platform.SimpleTextWatcher
@EpoxyModelClass(layout = R.layout.item_form_text_input)
abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
@EpoxyAttribute
var hint: String? = null
@EpoxyAttribute
var value: String? = null
@EpoxyAttribute
var enabled: Boolean = true
@EpoxyAttribute
var onTextChange: ((String) -> Unit)? = null
override fun bind(holder: Holder) {
holder.textInputLayout.isEnabled = enabled
holder.textInputLayout.hint = hint
// Update only if text is different
if (holder.textInputEditText.text.toString() != value) {
holder.textInputEditText.setText(value)
}
holder.textInputEditText.isEnabled = enabled
holder.textInputEditText.addTextChangedListener(object : SimpleTextWatcher() {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
onTextChange?.invoke(s.toString())
}
})
}
override fun shouldSaveViewState(): Boolean {
return true
}
override fun unbind(holder: Holder) {
super.unbind(holder)
// TODO Remove onTextChanged?
}
class Holder : VectorEpoxyHolder() {
val textInputLayout by bind<TextInputLayout>(R.id.formTextInputTextInputLayout)
val textInputEditText by bind<TextInputEditText>(R.id.formTextInputTextInputEditText)
}
}

View file

@ -0,0 +1,77 @@
/*
* 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.riotredesign.features.form
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import com.google.android.material.switchmaterial.SwitchMaterial
import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.core.extensions.setTextOrHide
@EpoxyModelClass(layout = R.layout.item_form_switch)
abstract class FormSwitchItem : VectorEpoxyModel<FormSwitchItem.Holder>() {
@EpoxyAttribute
var listener: ((Boolean) -> Unit)? = null
@EpoxyAttribute
var enabled: Boolean = true
@EpoxyAttribute
var switchChecked: Boolean = false
@EpoxyAttribute
var title: String? = null
@EpoxyAttribute
var summary: String? = null
override fun bind(holder: Holder) {
holder.titleView.text = title
holder.summaryView.setTextOrHide(summary)
holder.switchView.isEnabled = enabled
holder.switchView.isChecked = switchChecked
holder.switchView.setOnCheckedChangeListener { _, isChecked ->
listener?.invoke(isChecked)
}
}
override fun shouldSaveViewState(): Boolean {
return true
}
override fun unbind(holder: Holder) {
super.unbind(holder)
holder.switchView.setOnCheckedChangeListener(null)
}
class Holder : VectorEpoxyHolder() {
val titleView by bind<TextView>(R.id.formSwitchTitle)
val summaryView by bind<TextView>(R.id.formSwitchSummary)
val switchView by bind<SwitchMaterial>(R.id.formSwitchSwitch)
}
}

View file

@ -76,9 +76,8 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
.disposeOnDestroy() .disposeOnDestroy()
publicRoomsCreateNewRoom.setOnClickListener { publicRoomsCreateNewRoom.setOnClickListener {
// TODO homeActivityViewModel.createRoom() // TODO Not the best navigation pattern
(vectorBaseActivity as? RoomDirectoryActivity)?.gotoCreateRoom()
vectorBaseActivity.notImplemented()
} }
viewModel.joinRoomErrorLiveData.observe(this, Observer { viewModel.joinRoomErrorLiveData.observe(this, Observer {

View file

@ -19,7 +19,9 @@ package im.vector.riotredesign.features.roomdirectory
import android.os.Bundle import android.os.Bundle
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.extensions.addFragment import im.vector.riotredesign.core.extensions.addFragment
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
import im.vector.riotredesign.core.platform.VectorBaseActivity import im.vector.riotredesign.core.platform.VectorBaseActivity
import im.vector.riotredesign.features.roomdirectory.createroom.CreateRoomFragment
import org.koin.android.scope.ext.android.bindScope import org.koin.android.scope.ext.android.bindScope
import org.koin.android.scope.ext.android.getOrCreateScope import org.koin.android.scope.ext.android.getOrCreateScope
@ -40,4 +42,8 @@ class RoomDirectoryActivity : VectorBaseActivity() {
} }
} }
fun gotoCreateRoom() {
addFragmentToBackstack(CreateRoomFragment(), R.id.simpleFragmentContainer)
}
} }

View file

@ -17,11 +17,11 @@
package im.vector.riotredesign.features.roomdirectory package im.vector.riotredesign.features.roomdirectory
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotredesign.features.roomdirectory.createroom.CreateRoomController
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryListCreator import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryListCreator
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerController import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerController
import org.koin.dsl.module.module import org.koin.dsl.module.module
// TODO Ganfra: When do we create a new module?
class RoomDirectoryModule { class RoomDirectoryModule {
companion object { companion object {
@ -41,5 +41,14 @@ class RoomDirectoryModule {
scope(ROOM_DIRECTORY_SCOPE) { scope(ROOM_DIRECTORY_SCOPE) {
PublicRoomsController(get(), get()) PublicRoomsController(get(), get())
} }
/* ==========================================================================================
* Create room
* ========================================================================================== */
scope(ROOM_DIRECTORY_SCOPE) {
CreateRoomController(get(), get())
}
} }
} }

View file

@ -0,0 +1,112 @@
/*
* 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.riotredesign.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.riotredesign.R
import im.vector.riotredesign.core.epoxy.errorWithRetryItem
import im.vector.riotredesign.core.epoxy.loadingItem
import im.vector.riotredesign.core.error.ErrorFormatter
import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.features.form.formEditTextItem
import im.vector.riotredesign.features.form.formSwitchItem
class CreateRoomController(private val stringProvider: StringProvider,
private val errorFormatter: ErrorFormatter
) : TypedEpoxyController<CreateRoomViewState>() {
var listener: Listener? = null
var index = 0
override fun buildModels(viewState: CreateRoomViewState) {
val asyncCreateRoom = viewState.asyncCreateRoomRequest
when (asyncCreateRoom) {
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)
errorWithRetryItem {
id("error")
text(errorFormatter.toHumanReadable(asyncCreateRoom.error))
listener { listener?.retry() }
}
}
}
}
private fun buildForm(viewState: CreateRoomViewState, enableFormElement: Boolean) {
formEditTextItem {
id("name")
enabled(enableFormElement)
value(viewState.roomName)
hint(stringProvider.getString(R.string.create_room_name_hint))
onTextChange { text ->
listener?.onNameChange(text)
}
}
formSwitchItem {
id("public")
enabled(enableFormElement)
title(stringProvider.getString(R.string.create_room_public_title))
summary(stringProvider.getString(R.string.create_room_public_description))
switchChecked(viewState.isPublic)
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)
}
}
}
interface Listener {
fun onNameChange(newName: String)
fun setIsPublic(isPublic: Boolean)
fun setIsInRoomDirectory(isInRoomDirectory: Boolean)
fun retry()
}
}

View file

@ -0,0 +1,104 @@
/*
* 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.riotredesign.features.roomdirectory.createroom
import android.os.Bundle
import android.view.MenuItem
import androidx.recyclerview.widget.LinearLayoutManager
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotredesign.R
import im.vector.riotredesign.core.platform.VectorBaseFragment
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
import kotlinx.android.synthetic.main.fragment_create_room.*
import org.koin.android.ext.android.inject
import org.koin.android.scope.ext.android.bindScope
import org.koin.android.scope.ext.android.getOrCreateScope
import timber.log.Timber
class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
private val viewModel: CreateRoomViewModel by fragmentViewModel()
private val createRoomController: CreateRoomController by inject()
override fun getLayoutResId() = R.layout.fragment_create_room
override fun getMenuRes() = R.menu.vector_room_creation
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
vectorBaseActivity.setSupportActionBar(createRoomToolbar)
setupRecyclerView()
createRoomClose.setOnClickListener {
// TODO Not the best way to manage Fragment Backstack...
vectorBaseActivity.onBackPressed()
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_create_room -> {
viewModel.doCreateRoom()
true
}
else ->
super.onOptionsItemSelected(item)
}
}
private fun setupRecyclerView() {
val layoutManager = LinearLayoutManager(context)
createRoomForm.layoutManager = layoutManager
createRoomController.listener = this
createRoomForm.setController(createRoomController)
}
override fun onNameChange(newName: String) {
viewModel.setName(newName)
}
override fun setIsPublic(isPublic: Boolean) {
viewModel.setIsPublic(isPublic)
}
override fun setIsInRoomDirectory(isInRoomDirectory: Boolean) {
viewModel.setIsInRoomDirectory(isInRoomDirectory)
}
override fun retry() {
Timber.v("Retry")
viewModel.doCreateRoom()
}
override fun invalidate() = withState(viewModel) { state ->
if (state.asyncCreateRoomRequest is Success) {
vectorBaseActivity.notImplemented("navigate to freshly created room")
} else {
// Populate list with Epoxy
createRoomController.setData(state)
}
}
}

View file

@ -0,0 +1,80 @@
/*
* 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.riotredesign.features.roomdirectory.createroom
import com.airbnb.mvrx.*
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.room.model.create.CreateRoomPreset
import im.vector.riotredesign.core.platform.VectorViewModel
import org.koin.android.ext.android.get
class CreateRoomViewModel(initialState: CreateRoomViewState,
private val session: Session) : VectorViewModel<CreateRoomViewState>(initialState) {
companion object : MvRxViewModelFactory<CreateRoomViewModel, CreateRoomViewState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: CreateRoomViewState): CreateRoomViewModel? {
val currentSession = viewModelContext.activity.get<Session>()
return CreateRoomViewModel(state, currentSession)
}
}
fun setName(newName: String) = setState { copy(roomName = newName) }
fun setIsPublic(value: Boolean) = setState { copy(isPublic = value) }
fun setIsInRoomDirectory(isInRoomDirectory: Boolean) = setState { copy(isInRoomDirectory = isInRoomDirectory) }
fun doCreateRoom() = withState { state ->
if (state.asyncCreateRoomRequest is Loading || state.asyncCreateRoomRequest is Success) {
return@withState
}
setState {
copy(asyncCreateRoomRequest = Loading())
}
val createRoomParams = CreateRoomParams().apply {
name = state.roomName.takeIf { it.isNotBlank() }
// Directory visibility
visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE
preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
}
session.createRoom(createRoomParams, object : MatrixCallback<String> {
override fun onSuccess(data: String) {
setState {
copy(asyncCreateRoomRequest = Success(data))
}
}
override fun onFailure(failure: Throwable) {
setState {
copy(asyncCreateRoomRequest = Fail(failure))
}
}
})
}
}

View file

@ -0,0 +1,28 @@
/*
* 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.riotredesign.features.roomdirectory.createroom
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized
data class CreateRoomViewState(
val roomName: String = "",
val isPublic: Boolean = false,
val isInRoomDirectory: Boolean = false,
val asyncCreateRoomRequest: Async<String> = Uninitialized
) : MvRxState

View file

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="18"
android:viewportHeight="18">
<path
android:pathData="M16,2L2,16M2,2l14,14"
android:strokeLineJoin="round"
android:strokeWidth="2.333"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#03B381"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,71 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/createRoomToolbar"
android:layout_width="0dp"
android:layout_height="?actionBarSize"
android:elevation="4dp"
app:contentInsetStartWithNavigation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/createRoomClose"
android:layout_width="@dimen/layout_touch_size"
android:layout_height="@dimen/layout_touch_size"
android:scaleType="center"
android:src="@drawable/ic_x_18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/createRoomTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/create_room_title"
android:textColor="?riotx_text_primary"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/createRoomClose"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
<com.airbnb.epoxy.EpoxyRecyclerView
android:id="@+id/createRoomForm"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/createRoomToolbar"
tools:listitem="@layout/item_form_switch" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,62 @@
<?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/formSwitchTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginLeft="@dimen/layout_horizontal_margin"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:layout_marginRight="@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"
app:layout_constraintEnd_toStartOf="@+id/formSwitchSwitch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="@string/create_room_public_title" />
<TextView
android:id="@+id/formSwitchSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:textColor="?riotx_text_secondary"
android:textSize="14sp"
app:layout_constraintBottom_toTopOf="@+id/formSwitchDivider"
app:layout_constraintStart_toStartOf="@+id/formSwitchTitle"
app:layout_constraintTop_toBottomOf="@+id/formSwitchTitle"
tools:text="@string/create_room_public_description" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/formSwitchSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="19dp"
android:layout_marginRight="19dp"
app:layout_constraintBottom_toTopOf="@+id/formSwitchDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/formSwitchDivider"
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>

View file

@ -0,0 +1,39 @@
<?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">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/formTextInputTextInputLayout"
style="@style/VectorTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
app:layout_constraintBottom_toTopOf="@+id/formTextInputDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/formTextInputTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:hint="@string/create_room_name_hint" />
</com.google.android.material.textfield.TextInputLayout>
<View
android:id="@+id/formTextInputDivider"
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>

View file

@ -2,13 +2,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context="org.matrix.vector.activity.VectorRoomCreationActivity"> tools:context=".features.roomdirectory.RoomDirectoryActivity">
<item <item
android:id="@+id/action_create_room" android:id="@+id/action_create_room"
android:icon="@drawable/ic_material_done_white" android:title="@string/create_room_action_create"
android:orderInCategory="0"
android:title="@string/room_participants_create"
app:showAsAction="always" /> app:showAsAction="always" />
</menu> </menu>

View file

@ -27,4 +27,7 @@
<dimen name="pill_min_height">20dp</dimen> <dimen name="pill_min_height">20dp</dimen>
<dimen name="pill_text_padding">4dp</dimen> <dimen name="pill_text_padding">4dp</dimen>
<dimen name="item_form_min_height">76dp</dimen>
</resources> </resources>

View file

@ -42,4 +42,13 @@
<string name="fab_menu_create_room">"Rooms"</string> <string name="fab_menu_create_room">"Rooms"</string>
<string name="fab_menu_create_chat">"Direct Messages"</string> <string name="fab_menu_create_chat">"Direct Messages"</string>
<!-- Create room screen -->
<string name="create_room_title">"New Room"</string>
<string name="create_room_action_create">"CREATE"</string>
<string name="create_room_name_hint">"Room name"</string>
<string name="create_room_public_title">"Public"</string>
<string name="create_room_public_description">"Anyone will be able to join this room"</string>
<string name="create_room_directory_title">"Room Directory"</string>
<string name="create_room_directory_description">"Publish this room in the room directory"</string>
</resources> </resources>