Refactoring/ create custom view for composerLayout in timeline

+ simplify quote/edit composer preview animation
This commit is contained in:
Valere 2019-05-25 14:49:35 +02:00
parent 3c16701766
commit b45cc0e63f
8 changed files with 224 additions and 123 deletions

View File

@ -1,41 +0,0 @@
package im.vector.riotredesign.core.utils

import android.view.animation.OvershootInterpolator
import androidx.annotation.LayoutRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.transition.ChangeBounds
import androidx.transition.Transition
import androidx.transition.TransitionManager


inline fun ConstraintLayout.updateConstraintSet(@LayoutRes layoutId: Int,
rootLayoutForAnimation: ConstraintLayout? = null,
noinline onAnimationEnd: (() -> Unit)? = null) {
if (rootLayoutForAnimation != null) {
val transition = ChangeBounds()
transition.interpolator = OvershootInterpolator()
transition.addListener(object : Transition.TransitionListener {
override fun onTransitionResume(transition: Transition) {
}

override fun onTransitionPause(transition: Transition) {
}

override fun onTransitionCancel(transition: Transition) {
}

override fun onTransitionStart(transition: Transition) {
}

override fun onTransitionEnd(transition: Transition) {
onAnimationEnd?.invoke()
}
})
TransitionManager.beginDelayedTransition(rootLayoutForAnimation, transition)
}
ConstraintSet().also {
it.clone(this@updateConstraintSet.context, layoutId)
it.applyTo(this@updateConstraintSet)
}
}

View File

@ -32,11 +32,9 @@ import android.view.HapticFeedbackConstants
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.ImageButton
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
@ -79,6 +77,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer
import im.vector.riotredesign.features.home.HomeModule import im.vector.riotredesign.features.home.HomeModule
import im.vector.riotredesign.features.home.HomePermalinkHandler import im.vector.riotredesign.features.home.HomePermalinkHandler
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerActions import im.vector.riotredesign.features.home.room.detail.composer.TextComposerActions
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerView
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewModel import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewModel
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewState import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewState
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
@ -96,7 +95,7 @@ import im.vector.riotredesign.features.media.VideoMediaViewerActivity
import im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity import im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_detail.* import kotlinx.android.synthetic.main.fragment_room_detail.*
import kotlinx.android.synthetic.main.include_composer_layout.* import kotlinx.android.synthetic.main.merge_composer_layout.view.*
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
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
@ -170,14 +169,8 @@ class RoomDetailFragment :


private lateinit var actionViewModel: ActionsHandler private lateinit var actionViewModel: ActionsHandler


@BindView(R.id.composer_related_message_sender)
lateinit var composerRelatedMessageTitle: TextView
@BindView(R.id.composer_related_message_preview)
lateinit var composerRelatedMessageContent: TextView
@BindView(R.id.composerLayout) @BindView(R.id.composerLayout)
lateinit var composerLayout: ConstraintLayout lateinit var composerLayout: TextComposerView
@BindView(R.id.rootConstraintLayout)
lateinit var rootConstraintLayout: ConstraintLayout


override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
@ -211,10 +204,8 @@ class RoomDetailFragment :
commandAutocompletePolicy.enabled = true commandAutocompletePolicy.enabled = true
val uid = session.sessionParams.credentials.userId val uid = session.sessionParams.credentials.userId
val meMember = session.getRoom(roomId)?.getRoomMember(uid) val meMember = session.getRoom(roomId)?.getRoomMember(uid)
AvatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composer_avatar_view) AvatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView)
composerLayout.updateConstraintSet(R.layout.constraint_set_composer_layout_compact, rootConstraintLayout) { composerLayout.collapse()
focusComposerAndShowKeyboard()
}
} }
SendMode.EDIT, SendMode.EDIT,
SendMode.QUOTE -> { SendMode.QUOTE -> {
@ -225,40 +216,37 @@ class RoomDetailFragment :
return@selectSubscribe return@selectSubscribe
} }
//switch to expanded bar //switch to expanded bar
composerRelatedMessageTitle.text = event.senderName composerLayout.composerRelatedMessageTitle.apply {
composerRelatedMessageTitle.setTextColor( text = event.senderName
ContextCompat.getColor(requireContext(), AvatarRenderer.getColorFromUserId(event.root.sender setTextColor(ContextCompat.getColor(requireContext(), AvatarRenderer.getColorFromUserId(event.root.sender
?: "")) ?: "")))
) }


//TODO this is used at several places, find way to refactor?
val messageContent: MessageContent? = val messageContent: MessageContent? =
event.annotations?.editSummary?.aggregatedContent?.toModel() event.annotations?.editSummary?.aggregatedContent?.toModel()
?: event.root.content.toModel() ?: event.root.content.toModel()
val eventTextBody = messageContent?.body val eventTextBody = messageContent?.body
composerRelatedMessageContent.text = eventTextBody composerLayout.composerRelatedMessageContent.text = eventTextBody




if (mode == SendMode.EDIT) { if (mode == SendMode.EDIT) {
composerEditText.setText(eventTextBody) composerLayout.composerEditText.setText(eventTextBody)
composer_related_message_action_image.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_edit)) composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_edit))
} else { } else {
composerEditText.setText("") composerLayout.composerEditText.setText("")
composer_related_message_action_image.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_quote)) composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_quote))
} }


AvatarRenderer.render(event.senderAvatar, event.root.sender AvatarRenderer.render(event.senderAvatar, event.root.sender
?: "", event.senderName, composer_avatar_view) ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar)


composerEditText.setSelection(composerEditText.text.length) composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length)
composerLayout.updateConstraintSet(R.layout.constraint_set_composer_layout_expanded, rootConstraintLayout) { composerLayout.expand {
focusComposerAndShowKeyboard() focusComposerAndShowKeyboard()
} }

composerLayout.composerRelatedMessageCloseButton.setOnClickListener {
view?.findViewById<ImageButton>(R.id.composer_related_message_close)?.setOnClickListener { composerLayout.composerEditText.setText("")

composerRelatedMessageTitle.text = ""
composerRelatedMessageContent.text = ""
composerEditText.setText("")
roomDetailViewModel.resetSendMode() roomDetailViewModel.resetSendMode()
} }


@ -323,7 +311,7 @@ class RoomDetailFragment :
private fun setupComposer() { private fun setupComposer() {
val elevation = 6f val elevation = 6f
val backgroundDrawable = ColorDrawable(Color.WHITE) val backgroundDrawable = ColorDrawable(Color.WHITE)
Autocomplete.on<Command>(composerEditText) Autocomplete.on<Command>(composerLayout.composerEditText)
.with(commandAutocompletePolicy) .with(commandAutocompletePolicy)
.with(autocompleteCommandPresenter) .with(autocompleteCommandPresenter)
.with(elevation) .with(elevation)
@ -343,7 +331,7 @@ class RoomDetailFragment :
.build() .build()


autocompleteUserPresenter.callback = this autocompleteUserPresenter.callback = this
Autocomplete.on<User>(composerEditText) Autocomplete.on<User>(composerLayout.composerEditText)
.with(CharPolicy('@', true)) .with(CharPolicy('@', true))
.with(autocompleteUserPresenter) .with(autocompleteUserPresenter)
.with(elevation) .with(elevation)
@ -371,7 +359,7 @@ class RoomDetailFragment :
// Add the span // Add the span
val user = session.getUser(item.userId) val user = session.getUser(item.userId)
val span = PillImageSpan(glideRequests, context!!, item.userId, user) val span = PillImageSpan(glideRequests, context!!, item.userId, user)
span.bind(composerEditText) span.bind(composerLayout.composerEditText)


editable.setSpan(span, startIndex, startIndex + displayName.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) editable.setSpan(span, startIndex, startIndex + displayName.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)


@ -383,8 +371,8 @@ class RoomDetailFragment :
}) })
.build() .build()


sendButton.setOnClickListener { composerLayout.sendButton.setOnClickListener {
val textMessage = composerEditText.text.toString() val textMessage = composerLayout.composerEditText.text.toString()
if (textMessage.isNotBlank()) { if (textMessage.isNotBlank()) {
roomDetailViewModel.process(RoomDetailActions.SendMessage(textMessage)) roomDetailViewModel.process(RoomDetailActions.SendMessage(textMessage))
} }
@ -392,7 +380,7 @@ class RoomDetailFragment :
} }


private fun setupAttachmentButton() { private fun setupAttachmentButton() {
attachmentButton.setOnClickListener { composerLayout.attachmentButton.setOnClickListener {
val intent = Intent(requireContext(), FilePickerActivity::class.java) val intent = Intent(requireContext(), FilePickerActivity::class.java)
intent.putExtra(FilePickerActivity.CONFIGS, Configurations.Builder() intent.putExtra(FilePickerActivity.CONFIGS, Configurations.Builder()
.setCheckPermission(true) .setCheckPermission(true)
@ -479,7 +467,7 @@ class RoomDetailFragment :


val uid = session.sessionParams.credentials.userId val uid = session.sessionParams.credentials.userId
val meMember = session.getRoom(state.roomId)?.getRoomMember(uid) val meMember = session.getRoom(state.roomId)?.getRoomMember(uid)
AvatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composer_avatar_view) AvatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView)


} else if (summary?.membership == Membership.INVITE && inviter != null) { } else if (summary?.membership == Membership.INVITE && inviter != null) {
inviteView.visibility = View.VISIBLE inviteView.visibility = View.VISIBLE
@ -511,7 +499,7 @@ class RoomDetailFragment :
is SendMessageResult.MessageSent, is SendMessageResult.MessageSent,
is SendMessageResult.SlashCommandHandled -> { is SendMessageResult.SlashCommandHandled -> {
// Clear composer // Clear composer
composerEditText.text = null composerLayout.composerEditText.text = null
} }
is SendMessageResult.SlashCommandError -> { is SendMessageResult.SlashCommandError -> {
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command)) displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
@ -705,6 +693,7 @@ class RoomDetailFragment :
* *
* @param text the text to insert. * @param text the text to insert.
*/ */
//TODO legacy, refactor
private fun insertUserDisplayNameInTextEditor(text: String?) { private fun insertUserDisplayNameInTextEditor(text: String?) {
//TODO move logic outside of fragment //TODO move logic outside of fragment
if (null != text) { if (null != text) {
@ -713,21 +702,21 @@ class RoomDetailFragment :
val myDisplayName = session.getUser(session.sessionParams.credentials.userId)?.displayName val myDisplayName = session.getUser(session.sessionParams.credentials.userId)?.displayName
if (TextUtils.equals(myDisplayName, text)) { if (TextUtils.equals(myDisplayName, text)) {
// current user // current user
if (TextUtils.isEmpty(composerEditText.text)) { if (TextUtils.isEmpty(composerLayout.composerEditText.text)) {
composerEditText.append(Command.EMOTE.command + " ") composerLayout.composerEditText.append(Command.EMOTE.command + " ")
composerEditText.setSelection(composerEditText.text.length) composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length)
// vibrate = true // vibrate = true
} }
} else { } else {
// another user // another user
if (TextUtils.isEmpty(composerEditText.text)) { if (TextUtils.isEmpty(composerLayout.composerEditText.text)) {
// Ensure displayName will not be interpreted as a Slash command // Ensure displayName will not be interpreted as a Slash command
if (text.startsWith("/")) { if (text.startsWith("/")) {
composerEditText.append("\\") composerLayout.composerEditText.append("\\")
} }
composerEditText.append(sanitizeDisplayname(text)!! + ": ") composerLayout.composerEditText.append(sanitizeDisplayname(text)!! + ": ")
} else { } else {
composerEditText.text.insert(composerEditText.selectionStart, sanitizeDisplayname(text)!! + " ") composerLayout.composerEditText.text.insert(composerLayout.composerEditText.selectionStart, sanitizeDisplayname(text)!! + " ")
} }


// vibrate = true // vibrate = true
@ -744,9 +733,9 @@ class RoomDetailFragment :
} }


private fun focusComposerAndShowKeyboard() { private fun focusComposerAndShowKeyboard() {
composerEditText.requestFocus() composerLayout.composerEditText.requestFocus()
val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.showSoftInput(composerEditText, InputMethodManager.SHOW_IMPLICIT) imm?.showSoftInput(composerLayout.composerEditText, InputMethodManager.SHOW_IMPLICIT)
} }


fun showSnackWithMessage(message: String, duration: Int = Snackbar.LENGTH_SHORT) { fun showSnackWithMessage(message: String, duration: Int = Snackbar.LENGTH_SHORT) {

View File

@ -0,0 +1,116 @@
package im.vector.riotredesign.features.home.room.detail.composer

import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.isVisible
import androidx.transition.AutoTransition
import androidx.transition.Transition
import androidx.transition.TransitionManager
import butterknife.BindView
import butterknife.ButterKnife
import im.vector.riotredesign.R


/**
* Encapsulate the timeline composer UX.
*
*/
class TextComposerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {

@BindView(R.id.composer_related_message_sender)
lateinit var composerRelatedMessageTitle: TextView
@BindView(R.id.composer_related_message_preview)
lateinit var composerRelatedMessageContent: TextView
@BindView(R.id.composer_related_message_avatar_view)
lateinit var composerRelatedMessageAvatar: ImageView
@BindView(R.id.composer_related_message_action_image)
lateinit var composerRelatedMessageActionIcon: ImageView
@BindView(R.id.composer_related_message_close)
lateinit var composerRelatedMessageCloseButton: ImageButton
@BindView(R.id.composerEditText)
lateinit var composerEditText: EditText
@BindView(R.id.composer_avatar_view)
lateinit var composerAvatarImageView: ImageView

var currentConstraintSetId: Int = -1


init {
inflate(context, R.layout.merge_composer_layout, this)
ButterKnife.bind(this)
collapse(false)
}


fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
if (currentConstraintSetId == R.layout.constraint_set_composer_layout_compact) {
//ignore we good
return
}
currentConstraintSetId = R.layout.constraint_set_composer_layout_compact
if (animate) {
val transition = AutoTransition()
// transition.duration = 5000
transition.addListener(object : Transition.TransitionListener {

override fun onTransitionEnd(transition: Transition) {
transitionComplete?.invoke()
}

override fun onTransitionResume(transition: Transition) {}

override fun onTransitionPause(transition: Transition) {}

override fun onTransitionCancel(transition: Transition) {}

override fun onTransitionStart(transition: Transition) {}
}
)
TransitionManager.beginDelayedTransition((parent as? ViewGroup ?: this), transition)
}
ConstraintSet().also {
it.clone(context, currentConstraintSetId)
it.applyTo(this)
}
}

fun expand(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
if (currentConstraintSetId == R.layout.constraint_set_composer_layout_expanded) {
//ignore we good
return
}
currentConstraintSetId = R.layout.constraint_set_composer_layout_expanded
if (animate) {
val transition = AutoTransition()
// transition.duration = 5000
transition.addListener(object : Transition.TransitionListener {

override fun onTransitionEnd(transition: Transition) {
transitionComplete?.invoke()
}

override fun onTransitionResume(transition: Transition) {}

override fun onTransitionPause(transition: Transition) {}

override fun onTransitionCancel(transition: Transition) {}

override fun onTransitionStart(transition: Transition) {}
}
)
TransitionManager.beginDelayedTransition((parent as? ViewGroup ?: this), transition)
}
ConstraintSet().also {
it.clone(context, currentConstraintSetId)
it.applyTo(this)
}
}
}

View File

@ -67,6 +67,13 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes


//TODO determine if can copy, forward, reply, quote, report? //TODO determine if can copy, forward, reply, quote, report?
val actions = ArrayList<SimpleAction>().apply { val actions = ArrayList<SimpleAction>().apply {

if (event.sendState == SendState.SENDING) {
//TODO add cancel?
return@apply
}
//TODO is downloading attachement?

this.add(SimpleAction(ACTION_ADD_REACTION, R.string.message_add_reaction, R.drawable.ic_add_reaction, event.root.eventId)) this.add(SimpleAction(ACTION_ADD_REACTION, R.string.message_add_reaction, R.drawable.ic_add_reaction, event.root.eventId))
if (canCopy(type)) { if (canCopy(type)) {
//TODO copy images? html? see ClipBoard //TODO copy images? html? see ClipBoard
@ -100,8 +107,6 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<Mes
//TODO //TODO
} }


//TODO is uploading
//TODO is downloading


if (event.sendState == SendState.SENT) { if (event.sendState == SendState.SENT) {



View File

@ -31,11 +31,21 @@
<View <View
android:id="@+id/related_message_background_bottom_separator" android:id="@+id/related_message_background_bottom_separator"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="1dp"
android:background="?vctr_bottom_nav_background_border_color" android:background="?vctr_bottom_nav_background_border_color"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<ImageView
android:id="@+id/composer_related_message_avatar_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toStartOf="parent"
tools:src="@tools:sample/avatars" />


<TextView <TextView
android:id="@+id/composer_related_message_sender" android:id="@+id/composer_related_message_sender"
@ -79,6 +89,7 @@
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:src="@drawable/ic_close_round" android:src="@drawable/ic_close_round"
android:tint="@color/rosy_pink" android:tint="@color/rosy_pink"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent" app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintStart_toEndOf="parent" /> app:layout_constraintStart_toEndOf="parent" />



View File

@ -22,9 +22,9 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="1dp" android:layout_height="1dp"
android:background="?vctr_bottom_nav_background_border_color" android:background="?vctr_bottom_nav_background_border_color"
app:layout_constraintTop_toTopOf="@id/related_message_backround"
app:layout_constraintEnd_toEndOf="@id/related_message_backround" app:layout_constraintEnd_toEndOf="@id/related_message_backround"
app:layout_constraintStart_toStartOf="@+id/related_message_backround" /> app:layout_constraintStart_toStartOf="@+id/related_message_backround"
app:layout_constraintTop_toTopOf="@id/related_message_backround" />


<View <View
android:id="@+id/related_message_background_bottom_separator" android:id="@+id/related_message_background_bottom_separator"
@ -35,6 +35,20 @@
app:layout_constraintEnd_toEndOf="@id/related_message_backround" app:layout_constraintEnd_toEndOf="@id/related_message_backround"
app:layout_constraintStart_toStartOf="@+id/related_message_backround" /> app:layout_constraintStart_toStartOf="@+id/related_message_backround" />


<ImageView
android:id="@+id/composer_related_message_avatar_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@id/composer_related_message_action_image"
app:layout_constraintEnd_toStartOf="@+id/composer_related_message_sender"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/composer_related_message_sender"
tools:src="@tools:sample/avatars" />

<TextView <TextView
android:id="@+id/composer_related_message_sender" android:id="@+id/composer_related_message_sender"
android:layout_width="0dp" android:layout_width="0dp"
@ -42,7 +56,7 @@
android:layout_margin="8dp" android:layout_margin="8dp"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/composer_related_message_close" app:layout_constraintEnd_toStartOf="@id/composer_related_message_close"
app:layout_constraintStart_toEndOf="@id/composer_avatar_view" app:layout_constraintStart_toEndOf="@id/composer_related_message_avatar_view"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/first_names" /> tools:text="@tools:sample/first_names" />


@ -68,9 +82,9 @@
android:alpha="1" android:alpha="1"
android:tint="?android:attr/textColorTertiary" android:tint="?android:attr/textColorTertiary"
android:visibility="visible" android:visibility="visible"
app:layout_constraintEnd_toEndOf="@id/composer_avatar_view" app:layout_constraintEnd_toEndOf="@id/composer_related_message_avatar_view"
app:layout_constraintStart_toStartOf="@id/composer_avatar_view" app:layout_constraintStart_toStartOf="@id/composer_related_message_avatar_view"
app:layout_constraintTop_toBottomOf="@id/composer_avatar_view" app:layout_constraintTop_toBottomOf="@id/composer_related_message_avatar_view"
tools:src="@drawable/ic_edit" /> tools:src="@drawable/ic_edit" />




@ -90,16 +104,19 @@


<ImageView <ImageView
android:id="@+id/composer_avatar_view" android:id="@+id/composer_avatar_view"
android:layout_width="40dp" android:layout_width="32dp"
android:layout_height="40dp" android:layout_height="32dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@id/composer_related_message_action_image" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/composer_related_message_sender" app:layout_constraintEnd_toStartOf="@+id/composerEditText"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/composer_related_message_sender" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />




@ -149,7 +166,7 @@
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/sendButton" app:layout_constraintEnd_toStartOf="@+id/sendButton"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/composer_avatar_view"
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier" app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
tools:text="@tools:sample/lorem" /> tools:text="@tools:sample/lorem" />



View File

@ -77,20 +77,20 @@
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/composerDivider" app:layout_constraintBottom_toTopOf="@+id/composerLayout"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" app:layout_constraintTop_toBottomOf="@id/toolbar"
tools:listitem="@layout/item_timeline_event_text_message" /> tools:listitem="@layout/item_timeline_event_text_message" />


<View
android:id="@+id/composerDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?vctr_list_divider_color"
app:layout_constraintBottom_toTopOf="@+id/composerLayout" />


<include layout="@layout/include_composer_layout" /> <im.vector.riotredesign.features.home.room.detail.composer.TextComposerView
android:id="@+id/composerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />


<im.vector.riotredesign.features.invite.VectorInviteView <im.vector.riotredesign.features.invite.VectorInviteView
android:id="@+id/inviteView" android:id="@+id/inviteView"

View File

@ -1,14 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <merge 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"
android:id="@+id/composerLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:constraintSet="@layout/constraint_set_composer_layout_compact" tools:constraintSet="@layout/constraint_set_composer_layout_compact"
app:layout_constraintBottom_toBottomOf="parent" tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">


<!-- ======================== <!-- ========================
/!\ Constraints for this layout are defined in external layout files that are used as constraint set for animation. /!\ Constraints for this layout are defined in external layout files that are used as constraint set for animation.
@ -35,6 +32,13 @@
android:background="?vctr_bottom_nav_background_border_color" android:background="?vctr_bottom_nav_background_border_color"
tools:ignore="MissingConstraints" /> tools:ignore="MissingConstraints" />


<ImageView
android:id="@+id/composer_related_message_avatar_view"
android:layout_width="0dp"
android:layout_height="0dp"
tools:ignore="MissingConstraints"
tools:src="@tools:sample/avatars" />

<TextView <TextView
android:id="@+id/composer_related_message_sender" android:id="@+id/composer_related_message_sender"
android:layout_width="0dp" android:layout_width="0dp"
@ -120,4 +124,4 @@
android:textSize="14sp" android:textSize="14sp"
tools:ignore="MissingConstraints" /> tools:ignore="MissingConstraints" />


</androidx.constraintlayout.widget.ConstraintLayout> </merge>