Refactoring/ create custom view for composerLayout in timeline
+ simplify quote/edit composer preview animation
This commit is contained in:
parent
3c16701766
commit
b45cc0e63f
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue