Import composer 0.7.0.1 from Element Android - still WIP

This commit is contained in:
Benoit Marty 2022-11-25 16:30:03 +01:00 committed by Benoit Marty
parent 75ae6c521a
commit 0af3f3bfb7
29 changed files with 775 additions and 1033 deletions

View file

@ -36,7 +36,7 @@ mavericks = "3.0.1"
timber = "5.0.1" timber = "5.0.1"
coil = "2.2.1" coil = "2.2.1"
datetime = "0.4.0" datetime = "0.4.0"
wysiwyg = "0.4.0" wysiwyg = "0.7.0.1"
serialization-json = "1.4.1" serialization-json = "1.4.1"
[libraries] [libraries]

View file

@ -0,0 +1,45 @@
/*
* 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 io.element.android.x.core.ui
import android.content.res.Resources
import android.util.TypedValue
import androidx.annotation.Px
class DimensionConverter(val resources: Resources) {
@Px
fun dpToPx(dp: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp.toFloat(),
resources.displayMetrics
).toInt()
}
@Px
fun spToPx(sp: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp.toFloat(),
resources.displayMetrics
).toInt()
}
fun pxToDp(@Px px: Int): Int {
return (px.toFloat() / resources.displayMetrics.density).toInt()
}
}

View file

@ -0,0 +1,43 @@
/*
* 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 io.element.android.x.core.ui
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.core.content.getSystemService
fun View.hideKeyboard() {
val imm = context?.getSystemService<InputMethodManager>()
imm?.hideSoftInputFromWindow(windowToken, 0)
}
fun View.showKeyboard(andRequestFocus: Boolean = false) {
if (andRequestFocus) {
requestFocus()
}
val imm = context?.getSystemService<InputMethodManager>()
imm?.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}
fun View.setHorizontalPadding(padding: Int) {
setPadding(
padding,
paddingTop,
padding,
paddingBottom
)
}

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="?vctr_content_quaternary" />
<corners android:radius="@dimen/rich_text_composer_corner_radius_expanded" />
</shape>

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="?vctr_content_quaternary" />
<corners android:radius="@dimen/rich_text_composer_corner_radius_single_line" />
</shape>

View file

@ -43,13 +43,6 @@
<dimen name="menu_item_ripple_size">48dp</dimen> <dimen name="menu_item_ripple_size">48dp</dimen>
<dimen name="menu_item_width_small">34dp</dimen> <dimen name="menu_item_width_small">34dp</dimen>
<!-- Composer -->
<dimen name="composer_min_height">56dp</dimen>
<dimen name="composer_attachment_size">52dp</dimen>
<dimen name="composer_attachment_margin">1dp</dimen>
<dimen name="rich_text_composer_corner_radius_single_line">28dp</dimen>
<dimen name="rich_text_composer_corner_radius_expanded">14dp</dimen>
<dimen name="chat_bubble_margin_start">28dp</dimen> <dimen name="chat_bubble_margin_start">28dp</dimen>
<dimen name="chat_bubble_margin_end">6dp</dimen> <dimen name="chat_bubble_margin_end">6dp</dimen>
<dimen name="chat_bubble_fixed_size">350sp</dimen> <dimen name="chat_bubble_fixed_size">350sp</dimen>

View file

@ -4,7 +4,7 @@
<style name="Widget.Vector.EditText.Composer" parent="Widget.AppCompat.EditText"> <style name="Widget.Vector.EditText.Composer" parent="Widget.AppCompat.EditText">
<item name="android:background">@android:color/transparent</item> <item name="android:background">@android:color/transparent</item>
<item name="android:inputType">textCapSentences|textMultiLine</item> <item name="android:inputType">textCapSentences|textMultiLine</item>
<item name="android:maxLines">12</item> <item name="android:maxLines">10</item>
<item name="android:minHeight">48dp</item> <item name="android:minHeight">48dp</item>
<item name="android:padding">8dp</item> <item name="android:padding">8dp</item>
<item name="android:textSize">15sp</item> <item name="android:textSize">15sp</item>
@ -14,9 +14,12 @@
<style name="Widget.Vector.EditText.RichTextComposer" parent="Widget.AppCompat.EditText"> <style name="Widget.Vector.EditText.RichTextComposer" parent="Widget.AppCompat.EditText">
<item name="android:background">@android:color/transparent</item> <item name="android:background">@android:color/transparent</item>
<item name="android:inputType">textCapSentences|textMultiLine</item> <item name="android:inputType">textCapSentences|textMultiLine</item>
<item name="android:maxLines">12</item> <item name="android:maxLines">10</item>
<item name="android:minHeight">20dp</item> <item name="android:minHeight">40dp</item>
<item name="android:padding">0dp</item> <item name="android:paddingTop">10dp</item>
<item name="android:paddingBottom">10dp</item>
<item name="paddingStart">12dp</item>
<item name="android:clipToPadding">false</item>
<item name="android:textSize">15sp</item> <item name="android:textSize">15sp</item>
<item name="android:textColor">?vctr_message_text_color</item> <item name="android:textColor">?vctr_message_text_color</item>
</style> </style>

View file

@ -11,6 +11,7 @@ android {
dependencies { dependencies {
implementation(project(":libraries:elementresources")) implementation(project(":libraries:elementresources"))
implementation(project(":libraries:core"))
implementation(libs.wysiwyg) implementation(libs.wysiwyg)
implementation(libs.androidx.constraintlayout) implementation(libs.androidx.constraintlayout)
implementation("com.google.android.material:material:1.7.0") implementation("com.google.android.material:material:1.7.0")

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 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 io.element.android.x.textcomposer
sealed interface MessageComposerMode {
data class Normal(val content: CharSequence?) : MessageComposerMode
sealed class Special(open val event: Any /* TODO set correct type here */, open val defaultContent: CharSequence) : MessageComposerMode
data class Edit(override val event: Any, override val defaultContent: CharSequence) : Special(event, defaultContent)
class Quote(override val event: Any, override val defaultContent: CharSequence) : Special(event, defaultContent)
class Reply(override val event: Any, override val defaultContent: CharSequence) : Special(event, defaultContent)
}

View file

@ -20,36 +20,25 @@ import android.net.Uri
import android.text.Editable import android.text.Editable
import android.widget.EditText import android.widget.EditText
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
// Imported from Element Android // Imported from Element Android
interface MessageComposerView { interface MessageComposerView {
companion object {
const val MAX_LINES_WHEN_COLLAPSED = 10
}
val text: Editable? val text: Editable?
val formattedText: String? val formattedText: String?
val editText: EditText val editText: EditText
val emojiButton: ImageButton? val emojiButton: ImageButton?
val sendButton: ImageButton val sendButton: ImageButton
val attachmentButton: ImageButton val attachmentButton: ImageButton
val fullScreenButton: ImageButton?
val composerRelatedMessageTitle: TextView
val composerRelatedMessageContent: TextView
val composerRelatedMessageImage: ImageView
val composerRelatedMessageActionIcon: ImageView
val composerRelatedMessageAvatar: ImageView
var callback: Callback? var callback: Callback?
var isVisible: Boolean
fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null)
fun expand(animate: Boolean = true, transitionComplete: (() -> Unit)? = null)
fun setTextIfDifferent(text: CharSequence?): Boolean fun setTextIfDifferent(text: CharSequence?): Boolean
fun replaceFormattedContent(text: CharSequence) fun renderComposerMode(mode: MessageComposerMode)
fun toggleFullScreen(newValue: Boolean)
fun setInvisible(isInvisible: Boolean)
} }
interface Callback { interface Callback {
@ -65,4 +54,3 @@ interface Callback {
fun onExpandOrCompactChange() fun onExpandOrCompactChange()
fun onFullScreenModeChanged() fun onFullScreenModeChanged()
} }

View file

@ -16,55 +16,70 @@
package io.element.android.x.textcomposer package io.element.android.x.textcomposer
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.graphics.Color
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.AttributeSet import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.EditText import android.widget.EditText
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import androidx.core.view.isGone
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import com.google.android.material.shape.MaterialShapeDrawable
import io.element.android.wysiwyg.EditorEditText import io.element.android.wysiwyg.EditorEditText
import io.element.android.wysiwyg.inputhandlers.models.InlineFormat import io.element.android.wysiwyg.inputhandlers.models.InlineFormat
import io.element.android.x.element.resources.R as ElementR import io.element.android.x.core.ui.DimensionConverter
import io.element.android.x.core.ui.hideKeyboard
import io.element.android.x.core.ui.showKeyboard
import io.element.android.x.textcomposer.databinding.ComposerRichTextLayoutBinding import io.element.android.x.textcomposer.databinding.ComposerRichTextLayoutBinding
import io.element.android.x.textcomposer.databinding.ViewRichTextMenuButtonBinding import io.element.android.x.textcomposer.databinding.ViewRichTextMenuButtonBinding
import io.element.android.x.textcomposer.tools.animateLayoutChange
import io.element.android.x.textcomposer.tools.setTextIfDifferent import io.element.android.x.textcomposer.tools.setTextIfDifferent
import uniffi.wysiwyg_composer.ActionState
import uniffi.wysiwyg_composer.ComposerAction import uniffi.wysiwyg_composer.ComposerAction
import uniffi.wysiwyg_composer.MenuState import io.element.android.x.element.resources.R as ElementR
// Imported from Element Android // Imported from Element Android
class RichTextComposerLayout @JvmOverloads constructor( class RichTextComposerLayout @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = 0 defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), MessageComposerView { ) : LinearLayout(context, attrs, defStyleAttr), MessageComposerView {
private val views: ComposerRichTextLayoutBinding private val views: ComposerRichTextLayoutBinding
override var callback: Callback? = null override var callback: Callback? = null
private var currentConstraintSetId: Int = -1 // There is no need to persist these values since they're always updated by the parent fragment
private val animationDuration = 100L private var isFullScreen = false
private val maxEditTextLinesWhenCollapsed = 12 private var hasRelatedMessage = false
private val isFullScreen: Boolean get() = currentConstraintSetId == R.layout.composer_rich_text_layout_constraint_set_fullscreen
var isTextFormattingEnabled = true var isTextFormattingEnabled = true
set(value) { set(value) {
if (field == value) return if (field == value) return
syncEditTexts() syncEditTexts()
field = value field = value
updateTextFieldBorder(isFullScreen)
updateEditTextVisibility() updateEditTextVisibility()
updateFullScreenButtonVisibility()
// If formatting is no longer enabled and it's in full screen, minimise the editor
if (!value && isFullScreen) {
callback?.onFullScreenModeChanged()
}
} }
override val text: Editable? override val text: Editable?
@ -83,39 +98,117 @@ class RichTextComposerLayout @JvmOverloads constructor(
get() = views.sendButton get() = views.sendButton
override val attachmentButton: ImageButton override val attachmentButton: ImageButton
get() = views.attachmentButton get() = views.attachmentButton
override val fullScreenButton: ImageButton?
get() = views.composerFullScreenButton // Border of the EditText
override val composerRelatedMessageActionIcon: ImageView private val borderShapeDrawable: MaterialShapeDrawable by lazy {
get() = views.composerRelatedMessageActionIcon MaterialShapeDrawable().apply {
override val composerRelatedMessageAvatar: ImageView val typedData = TypedValue()
get() = views.composerRelatedMessageAvatar val lineColor = context.theme.obtainStyledAttributes(
override val composerRelatedMessageContent: TextView typedData.data,
get() = views.composerRelatedMessageContent intArrayOf(ElementR.attr.vctr_content_quaternary)
override val composerRelatedMessageImage: ImageView )
get() = views.composerRelatedMessageImage .getColor(0, 0)
override val composerRelatedMessageTitle: TextView strokeColor = ColorStateList.valueOf(lineColor)
get() = views.composerRelatedMessageTitle strokeWidth = 1 * resources.displayMetrics.scaledDensity
override var isVisible: Boolean fillColor = ColorStateList.valueOf(Color.TRANSPARENT)
get() = views.root.isVisible val cornerSize =
set(value) { resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_single_line)
views.root.isVisible = value setCornerSize(cornerSize.toFloat())
} }
}
private val dimensionConverter = DimensionConverter(resources)
fun setFullScreen(isFullScreen: Boolean) {
editText.updateLayoutParams<ViewGroup.LayoutParams> {
height = if (isFullScreen) 0 else ViewGroup.LayoutParams.WRAP_CONTENT
}
updateTextFieldBorder(isFullScreen)
updateEditTextVisibility()
updateEditTextFullScreenState(views.richTextComposerEditText, isFullScreen)
updateEditTextFullScreenState(views.plainTextComposerEditText, isFullScreen)
views.composerFullScreenButton.setImageResource(
if (isFullScreen) R.drawable.ic_composer_collapse else R.drawable.ic_composer_full_screen
)
views.bottomSheetHandle.isVisible = isFullScreen
if (isFullScreen) {
editText.showKeyboard(true)
} else {
editText.hideKeyboard()
}
this.isFullScreen = isFullScreen
}
fun notifyIsBeingDragged(percentage: Float) {
// Calculate a new shape for the border according to the position in screen
val isSingleLine = editText.lineCount == 1
val cornerSize = if (!isSingleLine || hasRelatedMessage) {
resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_expanded)
.toFloat()
} else {
val multilineCornerSize =
resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_expanded)
val singleLineCornerSize =
resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_single_line)
val diff = singleLineCornerSize - multilineCornerSize
multilineCornerSize + diff * (1 - percentage)
}
if (cornerSize != borderShapeDrawable.bottomLeftCornerResolvedSize) {
borderShapeDrawable.setCornerSize(cornerSize)
}
// Change maxLines while dragging, this should improve the smoothness of animations
val maxLines = if (percentage > 0.25f) {
Int.MAX_VALUE
} else {
MessageComposerView.MAX_LINES_WHEN_COLLAPSED
}
views.richTextComposerEditText.maxLines = maxLines
views.plainTextComposerEditText.maxLines = maxLines
views.bottomSheetHandle.isVisible = true
}
init { init {
inflate(context, R.layout.composer_rich_text_layout, this) inflate(context, R.layout.composer_rich_text_layout, this)
views = ComposerRichTextLayoutBinding.bind(this) views = ComposerRichTextLayoutBinding.bind(this)
collapse(false) // Workaround to avoid cut-off text caused by padding in scrolled TextView (there is no clipToPadding).
// In TextView, clipTop = padding, but also clipTop -= shadowRadius. So if we set the shadowRadius to padding, they cancel each other
views.richTextComposerEditText.setShadowLayer(
views.richTextComposerEditText.paddingBottom.toFloat(),
0f,
0f,
0
)
views.plainTextComposerEditText.setShadowLayer(
views.richTextComposerEditText.paddingBottom.toFloat(),
0f,
0f,
0
)
renderComposerMode(MessageComposerMode.Normal(null))
views.richTextComposerEditText.addTextChangedListener( views.richTextComposerEditText.addTextChangedListener(
TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder() }) TextChangeListener(
{ callback?.onTextChanged(it) },
{ updateTextFieldBorder(isFullScreen) })
) )
views.plainTextComposerEditText.addTextChangedListener( views.plainTextComposerEditText.addTextChangedListener(
TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder() }) TextChangeListener(
{ callback?.onTextChanged(it) },
{ updateTextFieldBorder(isFullScreen) })
) )
views.composerRelatedMessageCloseButton.setOnClickListener { disallowParentInterceptTouchEvent(views.richTextComposerEditText)
collapse() disallowParentInterceptTouchEvent(views.plainTextComposerEditText)
views.composerModeCloseView.setOnClickListener {
callback?.onCloseRelatedMessage() callback?.onCloseRelatedMessage()
} }
@ -128,54 +221,73 @@ class RichTextComposerLayout @JvmOverloads constructor(
callback?.onAddAttachment() callback?.onAddAttachment()
} }
views.composerFullScreenButton.setOnClickListener { views.composerFullScreenButton.apply {
callback?.onFullScreenModeChanged() updateFullScreenButtonVisibility()
setOnClickListener {
callback?.onFullScreenModeChanged()
}
} }
views.composerEditTextOuterBorder.background = borderShapeDrawable
setupRichTextMenu() setupRichTextMenu()
updateTextFieldBorder(isFullScreen)
} }
private fun setupRichTextMenu() { private fun setupRichTextMenu() {
addRichTextMenuItem( addRichTextMenuItem(
ElementR.drawable.ic_composer_bold, ElementR.drawable.ic_composer_bold,
ElementR.string.rich_text_editor_format_bold, ElementR.string.rich_text_editor_format_bold,
ComposerAction.Bold ComposerAction.BOLD
) { ) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Bold) views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Bold)
} }
addRichTextMenuItem( addRichTextMenuItem(
ElementR.drawable.ic_composer_italic, ElementR.drawable.ic_composer_italic,
ElementR.string.rich_text_editor_format_italic, ElementR.string.rich_text_editor_format_italic,
ComposerAction.Italic ComposerAction.ITALIC
) { ) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Italic) views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Italic)
} }
addRichTextMenuItem( addRichTextMenuItem(
ElementR.drawable.ic_composer_underlined, ElementR.drawable.ic_composer_underlined,
ElementR.string.rich_text_editor_format_underline, ElementR.string.rich_text_editor_format_underline,
ComposerAction.Underline ComposerAction.UNDERLINE
) { ) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Underline) views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Underline)
} }
addRichTextMenuItem( addRichTextMenuItem(
ElementR.drawable.ic_composer_strikethrough, ElementR.drawable.ic_composer_strikethrough,
ElementR.string.rich_text_editor_format_strikethrough, ElementR.string.rich_text_editor_format_strikethrough,
ComposerAction.StrikeThrough ComposerAction.STRIKE_THROUGH
) { ) {
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.StrikeThrough) views.richTextComposerEditText.toggleInlineFormat(InlineFormat.StrikeThrough)
} }
} }
@SuppressLint("ClickableViewAccessibility")
private fun disallowParentInterceptTouchEvent(view: View) {
view.setOnTouchListener { v, event ->
if (v.hasFocus()) {
v.parent?.requestDisallowInterceptTouchEvent(true)
val action = event.actionMasked
if (action == MotionEvent.ACTION_SCROLL) {
v.parent?.requestDisallowInterceptTouchEvent(false)
return@setOnTouchListener true
}
}
false
}
}
override fun onAttachedToWindow() { override fun onAttachedToWindow() {
super.onAttachedToWindow() super.onAttachedToWindow()
views.richTextComposerEditText.menuStateChangedListener = views.richTextComposerEditText.actionStatesChangedListener =
EditorEditText.OnMenuStateChangedListener { state -> EditorEditText.OnActionStatesChangedListener { state ->
if (state is MenuState.Update) { for (action in state.keys) {
updateMenuStateFor(ComposerAction.Bold, state) updateMenuStateFor(action, state)
updateMenuStateFor(ComposerAction.Italic, state)
updateMenuStateFor(ComposerAction.Underline, state)
updateMenuStateFor(ComposerAction.StrikeThrough, state)
} }
} }
@ -186,6 +298,85 @@ class RichTextComposerLayout @JvmOverloads constructor(
views.richTextComposerEditText.isVisible = isTextFormattingEnabled views.richTextComposerEditText.isVisible = isTextFormattingEnabled
views.richTextMenu.isVisible = isTextFormattingEnabled views.richTextMenu.isVisible = isTextFormattingEnabled
views.plainTextComposerEditText.isVisible = !isTextFormattingEnabled views.plainTextComposerEditText.isVisible = !isTextFormattingEnabled
// The layouts for formatted text mode and plain text mode are different, so we need to update the constraints
val dpToPx = { dp: Int -> dimensionConverter.dpToPx(dp) }
ConstraintSet().apply {
clone(views.composerLayoutContent)
clear(R.id.composerEditTextOuterBorder, ConstraintSet.TOP)
clear(R.id.composerEditTextOuterBorder, ConstraintSet.BOTTOM)
clear(R.id.composerEditTextOuterBorder, ConstraintSet.START)
clear(R.id.composerEditTextOuterBorder, ConstraintSet.END)
if (isTextFormattingEnabled) {
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.TOP,
R.id.composerLayoutContent,
ConstraintSet.TOP,
dpToPx(8)
)
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.BOTTOM,
R.id.sendButton,
ConstraintSet.TOP,
0
)
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.START,
R.id.composerLayoutContent,
ConstraintSet.START,
dpToPx(12)
)
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.END,
R.id.composerLayoutContent,
ConstraintSet.END,
dpToPx(12)
)
} else {
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.TOP,
R.id.composerLayoutContent,
ConstraintSet.TOP,
dpToPx(10)
)
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.BOTTOM,
R.id.composerLayoutContent,
ConstraintSet.BOTTOM,
dpToPx(10)
)
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.START,
R.id.attachmentButton,
ConstraintSet.END,
0
)
connect(
R.id.composerEditTextOuterBorder,
ConstraintSet.END,
R.id.sendButton,
ConstraintSet.START,
0
)
}
applyTo(views.composerLayoutContent)
}
}
private fun updateFullScreenButtonVisibility() {
val isLargeScreenDevice =
resources.configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)
val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
// There's no point in having full screen in landscape since there's almost no vertical space
views.composerFullScreenButton.isInvisible =
!isTextFormattingEnabled || (isLandscape && !isLargeScreenDevice)
} }
/** /**
@ -193,9 +384,9 @@ class RichTextComposerLayout @JvmOverloads constructor(
*/ */
private fun syncEditTexts() = private fun syncEditTexts() =
if (isTextFormattingEnabled) { if (isTextFormattingEnabled) {
views.plainTextComposerEditText.setText(views.richTextComposerEditText.getPlainText()) views.plainTextComposerEditText.setText(views.richTextComposerEditText.getMarkdown())
} else { } else {
views.richTextComposerEditText.setText(views.plainTextComposerEditText.text.toString()) views.richTextComposerEditText.setMarkdown(views.plainTextComposerEditText.text.toString())
} }
private fun addRichTextMenuItem( private fun addRichTextMenuItem(
@ -216,91 +407,112 @@ class RichTextComposerLayout @JvmOverloads constructor(
} }
} }
private fun updateMenuStateFor(action: ComposerAction, menuState: MenuState.Update) { private fun updateMenuStateFor(
action: ComposerAction,
menuState: Map<ComposerAction, ActionState>
) {
val button = findViewWithTag<ImageButton>(action) ?: return val button = findViewWithTag<ImageButton>(action) ?: return
button.isEnabled = !menuState.disabledActions.contains(action) val stateForAction = menuState[action]
button.isSelected = menuState.reversedActions.contains(action) button.isEnabled = stateForAction != ActionState.DISABLED
button.isSelected = stateForAction == ActionState.REVERSED
} }
private fun updateTextFieldBorder() { fun estimateCollapsedHeight(): Int {
val isExpanded = editText.editableText.lines().count() > 1 val editText = this.editText
val borderResource = if (isExpanded || isFullScreen) { val originalLines = editText.maxLines
ElementR.drawable.bg_composer_rich_edit_text_expanded val originalParamsHeight = editText.layoutParams.height
editText.maxLines = MessageComposerView.MAX_LINES_WHEN_COLLAPSED
editText.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.UNSPECIFIED,
)
val result = measuredHeight
editText.layoutParams.height = originalParamsHeight
editText.maxLines = originalLines
return result
}
private fun updateTextFieldBorder(isFullScreen: Boolean) {
val isMultiline =
editText.editableText.lines().count() > 1 || isFullScreen || hasRelatedMessage
val cornerSize = if (isMultiline) {
resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_expanded)
} else { } else {
ElementR.drawable.bg_composer_rich_edit_text_single_line resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_single_line)
} }.toFloat()
views.composerEditTextOuterBorder.setBackgroundResource(borderResource) borderShapeDrawable.setCornerSize(cornerSize)
} }
override fun replaceFormattedContent(text: CharSequence) { private fun replaceFormattedContent(text: CharSequence) {
views.richTextComposerEditText.setHtml(text.toString()) views.richTextComposerEditText.setHtml(text.toString())
} updateTextFieldBorder(isFullScreen)
override fun collapse(animate: Boolean, transitionComplete: (() -> Unit)?) {
if (currentConstraintSetId == R.layout.composer_rich_text_layout_constraint_set_compact) {
// ignore we good
return
}
currentConstraintSetId = R.layout.composer_rich_text_layout_constraint_set_compact
applyNewConstraintSet(animate, transitionComplete)
updateEditTextVisibility()
}
override fun expand(animate: Boolean, transitionComplete: (() -> Unit)?) {
if (currentConstraintSetId == R.layout.composer_rich_text_layout_constraint_set_expanded) {
// ignore we good
return
}
currentConstraintSetId = R.layout.composer_rich_text_layout_constraint_set_expanded
applyNewConstraintSet(animate, transitionComplete)
updateEditTextVisibility()
} }
override fun setTextIfDifferent(text: CharSequence?): Boolean { override fun setTextIfDifferent(text: CharSequence?): Boolean {
return editText.setTextIfDifferent(text) val result = editText.setTextIfDifferent(text)
} updateTextFieldBorder(isFullScreen)
return result
override fun toggleFullScreen(newValue: Boolean) {
val constraintSetId =
if (newValue) R.layout.composer_rich_text_layout_constraint_set_fullscreen else currentConstraintSetId
ConstraintSet().also {
it.clone(context, constraintSetId)
it.applyTo(this)
}
updateTextFieldBorder()
updateEditTextVisibility()
updateEditTextFullScreenState(views.richTextComposerEditText, newValue)
updateEditTextFullScreenState(views.plainTextComposerEditText, newValue)
} }
private fun updateEditTextFullScreenState(editText: EditText, isFullScreen: Boolean) { private fun updateEditTextFullScreenState(editText: EditText, isFullScreen: Boolean) {
if (isFullScreen) { if (isFullScreen) {
editText.maxLines = Int.MAX_VALUE editText.maxLines = Int.MAX_VALUE
// This is a workaround to fix incorrect scroll position when maximised
post { editText.requestLayout() }
} else { } else {
editText.maxLines = maxEditTextLinesWhenCollapsed editText.maxLines = MessageComposerView.MAX_LINES_WHEN_COLLAPSED
} }
} }
private fun applyNewConstraintSet(animate: Boolean, transitionComplete: (() -> Unit)?) { override fun renderComposerMode(mode: MessageComposerMode) {
// val wasSendButtonInvisible = views.sendButton.isInvisible if (mode is MessageComposerMode.Special) {
if (animate) { views.composerModeGroup.isVisible = true
animateLayoutChange(animationDuration, transitionComplete) replaceFormattedContent(mode.defaultContent)
} hasRelatedMessage = true
ConstraintSet().also { editText.showKeyboard(andRequestFocus = true)
it.clone(context, currentConstraintSetId) } else {
it.applyTo(this) views.composerModeGroup.isGone = true
(mode as? MessageComposerMode.Normal)?.content?.let { text ->
if (isTextFormattingEnabled) {
replaceFormattedContent(text)
} else {
views.plainTextComposerEditText.setText(text)
}
}
views.sendButton.contentDescription = resources.getString(ElementR.string.action_send)
hasRelatedMessage = false
} }
// Might be updated by view state just after, but avoid blinks views.sendButton.apply {
// views.sendButton.isInvisible = wasSendButtonInvisible if (mode is MessageComposerMode.Edit) {
} contentDescription = resources.getString(ElementR.string.action_save)
setImageResource(R.drawable.ic_composer_rich_text_save)
} else {
contentDescription = resources.getString(ElementR.string.action_send)
setImageResource(R.drawable.ic_rich_composer_send)
}
}
override fun setInvisible(isInvisible: Boolean) { updateTextFieldBorder(isFullScreen)
this.isInvisible = isInvisible
when (mode) {
is MessageComposerMode.Edit -> {
views.composerModeTitleView.setText(R.string.editing)
views.composerModeIconView.setImageResource(R.drawable.ic_composer_rich_text_editor_edit)
}
is MessageComposerMode.Quote -> {
views.composerModeTitleView.setText(R.string.quoting)
views.composerModeIconView.setImageResource(R.drawable.ic_quote)
}
is MessageComposerMode.Reply -> {
// TODO We need sender info
// val senderInfo = mode.event.senderInfo
val userName = "TODO Sender name" // senderInfo.displayName ?: senderInfo.disambiguatedDisplayName
views.composerModeTitleView.text =
resources.getString(R.string.replying_to, userName)
views.composerModeIconView.setImageResource(R.drawable.ic_reply)
}
else -> Unit
}
} }
private class TextChangeListener( private class TextChangeListener(

View file

@ -55,8 +55,9 @@ fun TextComposer(
} }
} }
setFullScreen(fullscreen)
(this as MessageComposerView).apply { (this as MessageComposerView).apply {
setup(fullscreen, isInDarkMode) setup(isInDarkMode)
} }
} }
}, },
@ -68,14 +69,14 @@ fun TextComposer(
// whenever the state changes // whenever the state changes
// Example of Compose -> View communication // Example of Compose -> View communication
val messageComposerView = (view as MessageComposerView) val messageComposerView = (view as MessageComposerView)
messageComposerView.toggleFullScreen(fullscreen) view.setFullScreen(fullscreen)
messageComposerView.sendButton.isInvisible = !composerCanSendMessage messageComposerView.sendButton.isInvisible = !composerCanSendMessage
messageComposerView.setTextIfDifferent(composerText ?: "") messageComposerView.setTextIfDifferent(composerText ?: "")
} }
) )
} }
private fun MessageComposerView.setup(fullscreen: Boolean, isDarkMode: Boolean) { private fun MessageComposerView.setup(isDarkMode: Boolean) {
val editTextColor = if(isDarkMode){ val editTextColor = if(isDarkMode){
Color.WHITE Color.WHITE
}else{ }else{
@ -83,7 +84,6 @@ private fun MessageComposerView.setup(fullscreen: Boolean, isDarkMode: Boolean)
} }
editText.setTextColor(editTextColor) editText.setTextColor(editTextColor)
editText.setHintTextColor(editTextColor) editText.setHintTextColor(editTextColor)
toggleFullScreen(fullscreen)
editText.setHint(ElementR.string.room_message_placeholder) editText.setHint(ElementR.string.room_message_placeholder)
emojiButton?.isVisible = true emojiButton?.isVisible = true
sendButton.isVisible = true sendButton.isVisible = true

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?android:colorBackground"/>
<corners android:topLeftRadius="24dp" android:topRightRadius="24dp" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="?vctr_content_quinary"/>
<corners android:radius="4dp" />
</shape>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="#C1C6CD"
android:pathData="M10.708,10Q10.438,10 10.219,9.781Q10,9.562 10,9.292V4.542Q10,4.354 10.146,4.219Q10.292,4.083 10.458,4.083Q10.646,4.083 10.781,4.219Q10.917,4.354 10.917,4.542V8.438L16.375,3Q16.5,2.854 16.688,2.854Q16.875,2.854 17,3Q17.146,3.125 17.146,3.312Q17.146,3.5 17,3.625L11.562,9.083H15.458Q15.646,9.083 15.781,9.229Q15.917,9.375 15.917,9.542Q15.917,9.729 15.781,9.865Q15.646,10 15.458,10ZM3,17Q2.854,16.875 2.854,16.688Q2.854,16.5 3,16.375L8.438,10.917H4.542Q4.354,10.917 4.219,10.771Q4.083,10.625 4.083,10.458Q4.083,10.271 4.219,10.135Q4.354,10 4.542,10H9.292Q9.562,10 9.781,10.219Q10,10.438 10,10.708V15.458Q10,15.646 9.854,15.781Q9.708,15.917 9.542,15.917Q9.354,15.917 9.219,15.781Q9.083,15.646 9.083,15.458V11.562L3.625,17Q3.5,17.146 3.312,17.146Q3.125,17.146 3,17Z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="#C1C6CD"
android:pathData="M3.625,17.083Q3.354,17.083 3.135,16.865Q2.917,16.646 2.917,16.375V11.625Q2.917,11.438 3.062,11.302Q3.208,11.167 3.375,11.167Q3.562,11.167 3.698,11.302Q3.833,11.438 3.833,11.625V15.5L15.5,3.833H11.625Q11.438,3.833 11.302,3.688Q11.167,3.542 11.167,3.375Q11.167,3.188 11.302,3.052Q11.438,2.917 11.625,2.917H16.375Q16.646,2.917 16.865,3.135Q17.083,3.354 17.083,3.625V8.375Q17.083,8.562 16.938,8.698Q16.792,8.833 16.625,8.833Q16.438,8.833 16.302,8.698Q16.167,8.562 16.167,8.375V4.5L4.5,16.167H8.375Q8.562,16.167 8.698,16.312Q8.833,16.458 8.833,16.625Q8.833,16.812 8.698,16.948Q8.562,17.083 8.375,17.083Z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<path
android:pathData="M10.403,2.53C10.696,2.237 10.696,1.763 10.403,1.47C10.111,1.177 9.636,1.177 9.343,1.47L5.946,4.867L2.549,1.47C2.256,1.177 1.781,1.177 1.488,1.47C1.195,1.763 1.195,2.237 1.488,2.53L4.885,5.927L1.343,9.47C1.05,9.763 1.05,10.237 1.343,10.53C1.636,10.823 2.11,10.823 2.403,10.53L5.946,6.988L9.488,10.53C9.781,10.823 10.256,10.823 10.549,10.53C10.842,10.237 10.842,9.763 10.549,9.47L7.006,5.927L10.403,2.53Z"
android:fillColor="#8D97A5"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<path
android:pathData="M2.649,7.355C2.655,7.316 2.672,7.28 2.699,7.251L8.404,1.064C8.479,0.983 8.605,0.978 8.686,1.053L9.863,2.138C9.944,2.213 9.949,2.339 9.874,2.42L4.169,8.607C4.143,8.636 4.108,8.656 4.069,8.665L2.668,9.005C2.529,9.039 2.401,8.92 2.423,8.779L2.649,7.355Z"
android:fillColor="#8D97A5"/>
<path
android:pathData="M1.75,9.443C1.336,9.443 1,9.779 1,10.193C1,10.608 1.336,10.943 1.75,10.943L10.75,10.943C11.164,10.943 11.5,10.608 11.5,10.193C11.5,9.779 11.164,9.443 10.75,9.443L1.75,9.443Z"
android:fillColor="#8D97A5"/>
</vector>

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:fillColor="#0DBD8B"/>
<path
android:pathData="M9.818,18.787L14.705,23.818L26.182,12"
android:strokeLineJoin="round"
android:strokeWidth="2.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="14dp"
android:viewportWidth="20"
android:viewportHeight="14">
<path
android:pathData="M19,5H1M19,1H1M10,9H1M10,13H1"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#9E9E9E"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,11 @@
<vector android:autoMirrored="true" android:height="25dp"
android:viewportHeight="25" android:viewportWidth="25"
android:width="25dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#00000000"
android:pathData="M13.9217,19.5H16.0147C18.4917,19.5 20.4997,17.4106 20.4997,14.8333C20.4997,12.256 18.4917,10.1666 16.0147,10.1666H6.5449"
android:strokeColor="#000000" android:strokeLineCap="round" android:strokeWidth="2"/>
<path android:fillColor="#00000000"
android:pathData="M9.1988,5.5L4.5,10.214L9.1988,14.9281"
android:strokeColor="#000000" android:strokeLineCap="round"
android:strokeLineJoin="round" android:strokeWidth="2"/>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:fillColor="#F4F6FA"/>
<path
android:pathData="M11.251,18H24.751M18.001,11.25V24.75"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#737D8C"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<path
android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:fillColor="#0DBD8B"/>
<path
android:pathData="M27.83,19.085L12.26,26.867C11.21,27.391 10.119,26.266 10.632,25.24C10.632,25.24 12.561,21.343 13.092,20.322C13.623,19.301 14.231,19.124 19.874,18.395C20.083,18.368 20.253,18.21 20.253,18C20.253,17.79 20.083,17.632 19.874,17.605C14.231,16.876 13.623,16.699 13.092,15.678C12.561,14.658 10.632,10.76 10.632,10.76C10.119,9.734 11.21,8.609 12.26,9.133L27.83,16.915C28.725,17.362 28.725,18.638 27.83,19.085Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -1,185 +1,202 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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="match_parent" android:layout_height="match_parent"
tools:constraintSet="@layout/composer_rich_text_layout_constraint_set_compact" android:orientation="vertical"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> android:background="@drawable/bg_composer_rich_bottom_sheet">
<!-- ========================
/!\ Constraints for this layout are defined in external layout files that are used as constraint set for animation.
/!\ These 3 files must be modified to stay coherent!
======================== -->
<View
android:id="@+id/related_message_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?colorSurface"
tools:ignore="MissingConstraints" />
<View
android:id="@+id/related_message_background_top_separator"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?vctr_list_separator"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/composerRelatedMessageAvatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:importantForAccessibility="no"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/composerRelatedMessageTitle"
android:layout_width="0dp"
android:layout_height="0dp"
android:textStyle="bold"
tools:ignore="MissingConstraints"
tools:text="@tools:sample/first_names"
tools:visibility="gone" />
<TextView
android:id="@+id/composerRelatedMessageContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="3"
android:textColor="?vctr_message_text_color"
tools:ignore="MissingConstraints"
tools:text="@tools:sample/lorem"
tools:visibility="gone" />
<ImageView
android:id="@+id/composerRelatedMessageActionIcon"
android:layout_width="0dp"
android:layout_height="0dp"
android:importantForAccessibility="no"
app:tint="?vctr_content_primary"
tools:ignore="MissingConstraints,MissingPrefix" />
<ImageView
android:id="@+id/composerRelatedMessageImage"
android:layout_width="0dp"
android:layout_height="0dp"
android:importantForAccessibility="no"
tools:ignore="MissingPrefix" />
<ImageButton
android:id="@+id/composerRelatedMessageCloseButton"
android:layout_width="22dp"
android:layout_height="22dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/action_cancel"
android:src="@drawable/ic_close_round"
app:tint="?colorError"
tools:ignore="MissingConstraints,MissingPrefix" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/composer_preview_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="composerRelatedMessageContent,composerRelatedMessageActionIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageButton
android:id="@+id/attachmentButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/option_send_files"
android:paddingTop="2dp"
android:src="@drawable/ic_attachment"
tools:ignore="MissingConstraints" />
<FrameLayout <FrameLayout
android:id="@+id/composerEditTextOuterBorder" android:id="@+id/bottomSheetHandle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/bg_composer_rich_edit_text_single_line" />
<io.element.android.wysiwyg.EditorEditText
android:id="@+id/richTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="top" app:layout_constraintTop_toTopOf="parent"
android:textCursorDrawable="@null" app:layout_constraintStart_toStartOf="parent"
android:nextFocusLeft="@id/richTextComposerEditText" app:layout_constraintEnd_toEndOf="parent">
android:nextFocusUp="@id/richTextComposerEditText"
tools:hint="@string/room_message_placeholder"
tools:ignore="MissingConstraints"
tools:text="@tools:sample/lorem/random" />
<!-- Use a separate EditText for plain text editing while the rich text editor doesn't support this mode --> <View
<com.google.android.material.textfield.TextInputEditText android:layout_width="36dp"
android:id="@+id/plainTextComposerEditText" android:layout_height="5dp"
style="@style/Widget.Vector.EditText.RichTextComposer" android:layout_gravity="center_horizontal"
android:layout_width="0dp" android:layout_marginTop="8dp"
android:layout_height="wrap_content" android:background="@drawable/bottomsheet_handle" />
android:gravity="top"
android:nextFocusLeft="@id/plainTextComposerEditText"
android:nextFocusUp="@id/plainTextComposerEditText"
tools:hint="@string/room_message_placeholder"
tools:ignore="MissingConstraints"
tools:text="@tools:sample/lorem/random" />
<ImageButton </FrameLayout>
android:id="@+id/composerFullScreenButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/rich_text_editor_full_screen_toggle"
android:src="@drawable/ic_composer_full_screen"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder" />
<ImageButton <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sendButton" android:id="@+id/composerLayoutContent"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent">
android:background="@drawable/bg_send"
android:contentDescription="@string/action_send"
android:src="@drawable/ic_send"
tools:ignore="MissingConstraints" />
<HorizontalScrollView <ImageButton
android:id="@+id/richTextMenuScrollView" android:id="@+id/attachmentButton"
android:layout_width="0dp" android:layout_width="56dp"
android:layout_height="wrap_content" android:layout_height="60dp"
android:fillViewport="true" android:layout_margin="@dimen/composer_attachment_margin"
android:scrollbars="none" android:background="?android:attr/selectableItemBackground"
app:layout_constraintBottom_toBottomOf="parent" android:contentDescription="@string/option_send_files"
app:layout_constraintEnd_toStartOf="@id/sendButton" android:src="@drawable/ic_rich_composer_add"
app:layout_constraintStart_toEndOf="@id/attachmentButton" android:paddingStart="4dp"
app:layout_constraintTop_toTopOf="@id/sendButton"> app:layout_constraintVertical_bias="1"
app:layout_constraintBottom_toBottomOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_goneMarginBottom="57dp"
tools:ignore="MissingPrefix,RtlSymmetry" />
<LinearLayout <FrameLayout
android:id="@+id/richTextMenu" android:id="@+id/composerEditTextOuterBorder"
android:layout_width="0dp"
android:layout_height="0dp"
android:minHeight="40dp"
android:layout_marginTop="8dp"
android:layout_marginHorizontal="12dp"
app:layout_constraintVertical_bias="0"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/composerModeIconView"
android:layout_width="11dp"
android:layout_height="11dp"
tools:src="@drawable/ic_quote"
android:layout_marginStart="12dp"
app:layout_constraintTop_toTopOf="@id/composerModeTitleView"
app:layout_constraintBottom_toBottomOf="@id/composerModeTitleView"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:tint="?vctr_content_tertiary" />
<TextView android:id="@+id/composerModeTitleView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:layout_marginStart="6dp"
android:layout_marginTop="8dp"
android:paddingBottom="2dp"
android:fontFamily="sans-serif-medium"
tools:text="Editing"
style="@style/BottomSheetItemTime"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
app:layout_constraintStart_toEndOf="@id/composerModeIconView" />
</LinearLayout> <ImageButton android:id="@+id/composerModeCloseView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_composer_rich_text_editor_close"
android:background="?android:selectableItemBackground"
android:layout_marginEnd="12dp"
android:contentDescription="@string/action_close"
app:layout_constraintTop_toTopOf="@id/composerModeIconView"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder" />
</HorizontalScrollView> <androidx.constraintlayout.widget.Barrier
android:id="@+id/composerModeBarrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom"
app:constraint_referenced_ids="composerModeIconView,composerModeTitleView,composerModeCloseView" />
<!-- <androidx.constraintlayout.widget.Group
<ImageButton android:id="@+id/composerModeGroup"
android:id="@+id/voiceMessageMicButton" android:layout_width="0dp"
android:layout_width="32dp" android:layout_height="0dp"
android:layout_height="32dp" android:visibility="gone"
android:layout_marginEnd="12dp" tools:visibility="visible"
android:layout_marginBottom="12dp" app:constraint_referenced_ids="composerModeIconView,composerModeTitleView,composerModeCloseView" />
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/a11y_start_voice_message"
android:src="@drawable/ic_voice_mic" />
-->
</merge> <io.element.android.wysiwyg.EditorEditText
android:id="@+id/richTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_default="wrap"
android:gravity="top"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/richTextComposerEditText"
android:nextFocusUp="@id/richTextComposerEditText"
android:layout_marginStart="12dp"
android:imeOptions="flagNoExtractUi"
app:layout_constraintVertical_bias="0"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toBottomOf="@id/composerModeBarrier"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/plainTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_default="wrap"
android:visibility="gone"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/plainTextComposerEditText"
android:nextFocusUp="@id/plainTextComposerEditText"
android:layout_marginStart="12dp"
android:gravity="top"
android:imeOptions="flagNoExtractUi"
app:layout_constraintVertical_bias="0"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toBottomOf="@id/composerModeBarrier"
tools:text="@tools:sample/lorem/random" />
<ImageButton
android:id="@+id/composerFullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="4dp"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toBottomOf="@id/composerModeBarrier"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintVertical_bias="0"
android:src="@drawable/ic_composer_full_screen"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/rich_text_editor_full_screen_toggle" />
<ImageButton
android:id="@+id/sendButton"
android:layout_width="56dp"
android:layout_height="60dp"
android:paddingEnd="4dp"
android:contentDescription="@string/action_send"
android:scaleType="center"
android:src="@drawable/ic_rich_composer_send"
android:visibility="invisible"
android:background="?android:selectableItemBackground"
app:layout_constraintTop_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="1"
tools:ignore="MissingPrefix,RtlSymmetry"
tools:visibility="visible" />
<HorizontalScrollView android:id="@+id/richTextMenuScrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="52dp"
app:layout_constraintTop_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintStart_toEndOf="@id/attachmentButton"
app:layout_constraintEnd_toStartOf="@id/sendButton"
app:layout_constraintBottom_toBottomOf="parent"
android:fillViewport="true">
<LinearLayout
android:id="@+id/richTextMenu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingVertical="4dp">
</LinearLayout>
</HorizontalScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View file

@ -1,233 +0,0 @@
<?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:id="@+id/composerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<View
android:id="@+id/related_message_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?colorSurface"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="40dp" />
<View
android:id="@+id/related_message_background_top_separator"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?vctr_list_separator"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/composerRelatedMessageAvatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:importantForAccessibility="no"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toStartOf="parent" />
<TextView
android:id="@+id/composerRelatedMessageTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="bold"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@id/composerRelatedMessageContent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="@tools:sample/first_names" />
<TextView
android:id="@+id/composerRelatedMessageContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="@tools:sample/lorem/random" />
<ImageView
android:id="@+id/composerRelatedMessageActionIcon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="38dp"
android:alpha="0"
android:importantForAccessibility="no"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:tint="?vctr_content_primary"
tools:ignore="MissingConstraints,MissingPrefix"
tools:src="@drawable/ic_edit" />
<ImageView
android:id="@+id/composerRelatedMessageImage"
android:layout_width="0dp"
android:layout_height="0dp"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintStart_toEndOf="parent"
tools:ignore="MissingPrefix"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageButton
android:id="@+id/composerRelatedMessageCloseButton"
android:layout_width="22dp"
android:layout_height="22dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/action_cancel"
android:src="@drawable/ic_close_round"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintStart_toEndOf="parent"
app:tint="?colorError"
tools:ignore="MissingPrefix"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/composer_preview_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="composerRelatedMessageContent,composerRelatedMessageActionIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageButton
android:id="@+id/attachmentButton"
android:layout_width="@dimen/composer_attachment_size"
android:layout_height="@dimen/composer_attachment_size"
android:layout_margin="@dimen/composer_attachment_margin"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/option_send_files"
android:src="@drawable/ic_attachment"
app:layout_constraintVertical_bias="1"
app:layout_constraintBottom_toBottomOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_goneMarginBottom="57dp"
tools:ignore="MissingPrefix" />
<FrameLayout
android:id="@+id/composerEditTextOuterBorder"
android:layout_width="0dp"
android:layout_height="0dp"
android:minHeight="40dp"
android:layout_marginTop="8dp"
android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_composer_rich_edit_text_single_line"
app:layout_constraintVertical_bias="0"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<io.element.android.wysiwyg.EditorEditText
android:id="@+id/richTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/richTextComposerEditText"
android:nextFocusUp="@id/richTextComposerEditText"
android:layout_marginHorizontal="12dp"
android:layout_marginVertical="10dp"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/plainTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/plainTextComposerEditText"
android:nextFocusUp="@id/plainTextComposerEditText"
android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
<ImageButton
android:id="@+id/composerFullScreenButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintVertical_bias="0"
android:src="@drawable/ic_composer_full_screen"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/rich_text_editor_full_screen_toggle" />
<ImageButton
android:id="@+id/sendButton"
android:layout_width="56dp"
android:layout_height="@dimen/composer_min_height"
android:layout_marginEnd="2dp"
android:background="@drawable/bg_send"
android:contentDescription="@string/action_send"
android:scaleType="center"
android:src="@drawable/ic_send"
android:visibility="invisible"
app:layout_constraintTop_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="1"
tools:ignore="MissingPrefix"
tools:visibility="visible" />
<HorizontalScrollView android:id="@+id/richTextMenuScrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_constraintStart_toEndOf="@id/attachmentButton"
app:layout_constraintEnd_toStartOf="@id/sendButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="1"
android:fillViewport="true">
<LinearLayout
android:id="@+id/richTextMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
<!--
<ImageButton
android:id="@+id/voiceMessageMicButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/a11y_start_voice_message"
android:src="@drawable/ic_voice_mic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
-->
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,230 +0,0 @@
<?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:id="@+id/composerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<View
android:id="@+id/related_message_background"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?colorSurface"
app:layout_constraintBottom_toBottomOf="@id/composer_preview_barrier"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/related_message_background_top_separator"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="?vctr_list_separator"
app:layout_constraintEnd_toEndOf="@id/related_message_background"
app:layout_constraintStart_toStartOf="@id/related_message_background"
app:layout_constraintTop_toTopOf="@id/related_message_background" />
<ImageView
android:id="@+id/composerRelatedMessageAvatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="@id/composerRelatedMessageActionIcon"
app:layout_constraintEnd_toStartOf="@id/composerRelatedMessageTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/composerRelatedMessageTitle"
tools:src="@sample/user_round_avatars" />
<TextView
android:id="@+id/composerRelatedMessageTitle"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/composerRelatedMessageCloseButton"
app:layout_constraintStart_toEndOf="@id/composerRelatedMessageAvatar"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/first_names" />
<ImageView
android:id="@+id/composerRelatedMessageImage"
android:layout_width="100dp"
android:layout_height="66dp"
android:layout_marginTop="6dp"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/composerRelatedMessageTitle"
app:layout_constraintTop_toBottomOf="@id/composerRelatedMessageTitle"
tools:ignore="MissingPrefix"
tools:src="@tools:sample/backgrounds/scenic"
tools:visibility="visible" />
<TextView
android:id="@+id/composerRelatedMessageContent"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="?vctr_message_text_color"
app:layout_constrainedHeight="true"
app:layout_constraintEnd_toEndOf="@id/composerRelatedMessageTitle"
app:layout_constraintStart_toStartOf="@id/composerRelatedMessageTitle"
app:layout_constraintTop_toBottomOf="@id/composerRelatedMessageImage"
tools:text="@tools:sample/lorem/random" />
<ImageView
android:id="@+id/composerRelatedMessageActionIcon"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="38dp"
android:alpha="1"
android:importantForAccessibility="no"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="@id/composerRelatedMessageAvatar"
app:layout_constraintStart_toStartOf="@id/composerRelatedMessageAvatar"
app:layout_constraintTop_toBottomOf="@id/composerRelatedMessageAvatar"
app:tint="?vctr_content_primary"
tools:ignore="MissingPrefix"
tools:src="@drawable/ic_edit" />
<ImageButton
android:id="@+id/composerRelatedMessageCloseButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/action_cancel"
android:src="@drawable/ic_close_round"
app:layout_constraintBottom_toBottomOf="@id/composer_preview_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?colorError"
tools:ignore="MissingPrefix" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/composer_preview_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="composerRelatedMessageContent,composerRelatedMessageActionIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageButton
android:id="@+id/attachmentButton"
android:layout_width="@dimen/composer_attachment_size"
android:layout_height="@dimen/composer_attachment_size"
android:layout_margin="@dimen/composer_attachment_margin"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/option_send_files"
android:src="@drawable/ic_attachment"
app:layout_constraintBottom_toBottomOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_goneMarginBottom="57dp"
tools:ignore="MissingPrefix" />
<FrameLayout
android:id="@+id/composerEditTextOuterBorder"
android:layout_width="0dp"
android:layout_height="0dp"
android:minHeight="40dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="0dp"
android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_composer_rich_edit_text_single_line"
app:layout_constraintVertical_bias="0"
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
app:layout_constraintBottom_toTopOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<io.element.android.wysiwyg.EditorEditText
android:id="@+id/richTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/richTextComposerEditText"
android:nextFocusUp="@id/richTextComposerEditText"
android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/plainTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/plainTextComposerEditText"
android:nextFocusUp="@id/plainTextComposerEditText"
android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
<ImageButton
android:id="@+id/composerFullScreenButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintVertical_bias="0"
android:src="@drawable/ic_composer_full_screen"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/rich_text_editor_full_screen_toggle" />
<ImageButton
android:id="@+id/sendButton"
android:layout_width="56dp"
android:layout_height="@dimen/composer_min_height"
android:layout_marginEnd="2dp"
android:background="@drawable/bg_send"
android:contentDescription="@string/action_send"
android:scaleType="center"
android:src="@drawable/ic_send"
android:visibility="invisible"
app:layout_constraintTop_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="MissingPrefix"
tools:visibility="visible" />
<HorizontalScrollView android:id="@+id/richTextMenuScrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_constraintStart_toEndOf="@id/attachmentButton"
app:layout_constraintEnd_toStartOf="@id/sendButton"
app:layout_constraintBottom_toBottomOf="parent"
android:fillViewport="true">
<LinearLayout
android:id="@+id/richTextMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,234 +0,0 @@
<?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:id="@+id/composerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<View
android:id="@+id/related_message_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?colorSurface"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="40dp" />
<View
android:id="@+id/related_message_background_top_separator"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?vctr_list_separator"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/composerRelatedMessageAvatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:importantForAccessibility="no"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toStartOf="parent" />
<TextView
android:id="@+id/composerRelatedMessageTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textStyle="bold"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@id/composerRelatedMessageContent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="@tools:sample/first_names" />
<TextView
android:id="@+id/composerRelatedMessageContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="@tools:sample/lorem/random" />
<ImageView
android:id="@+id/composerRelatedMessageActionIcon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="38dp"
android:alpha="0"
android:importantForAccessibility="no"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:tint="?vctr_content_primary"
tools:ignore="MissingConstraints,MissingPrefix"
tools:src="@drawable/ic_edit" />
<ImageView
android:id="@+id/composerRelatedMessageImage"
android:layout_width="0dp"
android:layout_height="0dp"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintStart_toEndOf="parent"
tools:ignore="MissingPrefix"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageButton
android:id="@+id/composerRelatedMessageCloseButton"
android:layout_width="22dp"
android:layout_height="22dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/action_cancel"
android:src="@drawable/ic_close_round"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintStart_toEndOf="parent"
app:tint="?colorError"
tools:ignore="MissingPrefix"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/composer_preview_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="composerRelatedMessageContent,composerRelatedMessageActionIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageButton
android:id="@+id/attachmentButton"
android:layout_width="@dimen/composer_attachment_size"
android:layout_height="@dimen/composer_attachment_size"
android:layout_margin="@dimen/composer_attachment_margin"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/option_send_files"
android:src="@drawable/ic_attachment"
app:layout_constraintBottom_toBottomOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_goneMarginBottom="57dp"
app:layout_constraintVertical_bias="1"
tools:ignore="MissingPrefix" />
<FrameLayout
android:id="@+id/composerEditTextOuterBorder"
android:layout_width="0dp"
android:layout_height="0dp"
android:minHeight="40dp"
android:layout_marginTop="16dp"
android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_composer_rich_edit_text_expanded"
app:layout_constraintVertical_bias="0"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<io.element.android.wysiwyg.EditorEditText
android:id="@+id/richTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="0dp"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/richTextComposerEditText"
android:nextFocusUp="@id/richTextComposerEditText"
android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
android:gravity="top"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/plainTextComposerEditText"
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="0dp"
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/plainTextComposerEditText"
android:nextFocusUp="@id/plainTextComposerEditText"
android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
android:gravity="top"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
<ImageButton
android:id="@+id/composerFullScreenButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
app:layout_constraintVertical_bias="0"
android:src="@drawable/ic_composer_full_screen"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/rich_text_editor_full_screen_toggle" />
<ImageButton
android:id="@+id/sendButton"
android:layout_width="56dp"
android:layout_height="@dimen/composer_min_height"
android:layout_marginEnd="2dp"
android:background="@drawable/bg_send"
android:contentDescription="@string/action_send"
android:scaleType="center"
android:src="@drawable/ic_send"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="1"
tools:ignore="MissingPrefix"
tools:visibility="visible" />
<HorizontalScrollView android:id="@+id/richTextMenuScrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/sendButton"
app:layout_constraintStart_toEndOf="@id/attachmentButton"
app:layout_constraintEnd_toStartOf="@id/sendButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="1"
android:fillViewport="true">
<LinearLayout
android:id="@+id/richTextMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
<!--
<ImageButton
android:id="@+id/voiceMessageMicButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/a11y_start_voice_message"
android:src="@drawable/ic_voice_mic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
-->
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="composer_min_height">56dp</dimen>
<dimen name="composer_attachment_size">52dp</dimen>
<dimen name="composer_attachment_margin">1dp</dimen>
<dimen name="rich_text_composer_corner_radius_single_line">28dp</dimen>
<dimen name="rich_text_composer_corner_radius_expanded">14dp</dimen>
<dimen name="rich_text_composer_menu_item_size">44dp</dimen>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="editing">Editing</string>
<string name="replying_to">Replying to %s</string>
<string name="quoting">Quoting</string>
</resources>