New RTE full screen implementation with BottomSheet (#7578)
* RTE full screen editor using custom BottomSheet * Fix formatting menu item dimensions * Fix bug with insets when opening attachment menu * Clear the EditText for plain text mode when a message is sent * Set `MessageComposerMode.Special` as a sealed class * Fix insets issue on landscape * Fix small UI issues with rounded corners * Use simplified icons for full screen and minimise
This commit is contained in:
parent
65d898e3de
commit
7417241cd5
1
changelog.d/7577.feature
Normal file
1
changelog.d/7577.feature
Normal file
@ -0,0 +1 @@
|
||||
New implementation of the full screen mode for the Rich Text Editor.
|
@ -1642,7 +1642,10 @@
|
||||
<string name="error_user_already_logged_in">It looks like you’re trying to connect to another homeserver. Do you want to sign out?</string>
|
||||
|
||||
<string name="edit">Edit</string>
|
||||
<string name="editing">Editing</string>
|
||||
<string name="reply">Reply</string>
|
||||
<string name="replying_to">Replying to %s</string>
|
||||
<string name="quoting">Quoting</string>
|
||||
<string name="reply_in_thread">Reply in thread</string>
|
||||
<string name="view_in_room">View In Room</string>
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
<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>
|
||||
|
||||
<dimen name="chat_bubble_margin_start">28dp</dimen>
|
||||
<dimen name="chat_bubble_margin_end">6dp</dimen>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<style name="Widget.Vector.EditText.Composer" parent="Widget.AppCompat.EditText">
|
||||
<item name="android:background">@android:color/transparent</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:padding">8dp</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
@ -14,9 +14,12 @@
|
||||
<style name="Widget.Vector.EditText.RichTextComposer" parent="Widget.AppCompat.EditText">
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:inputType">textCapSentences|textMultiLine</item>
|
||||
<item name="android:maxLines">12</item>
|
||||
<item name="android:minHeight">20dp</item>
|
||||
<item name="android:padding">0dp</item>
|
||||
<item name="android:maxLines">10</item>
|
||||
<item name="android:minHeight">40dp</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:textColor">?vctr_message_text_color</item>
|
||||
</style>
|
||||
|
@ -0,0 +1,791 @@
|
||||
package im.vector.app.core.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.VelocityTracker
|
||||
import android.view.View
|
||||
import android.view.View.MeasureSpec
|
||||
import android.view.ViewGroup
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsAnimationCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.customview.widget.ViewDragHelper
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import timber.log.Timber
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* BottomSheetBehavior that dynamically resizes its contents as it grows or shrinks.
|
||||
* Most of the nested scrolling and touch events code is the same as in [BottomSheetBehavior], but we couldn't just extend it.
|
||||
*/
|
||||
class ExpandingBottomSheetBehavior<V : View> : CoordinatorLayout.Behavior<V> {
|
||||
|
||||
companion object {
|
||||
/** Gets a [ExpandingBottomSheetBehavior] from the passed [view] if it exists. */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <V : View> from(view: V): ExpandingBottomSheetBehavior<V>? {
|
||||
val params = view.layoutParams as? CoordinatorLayout.LayoutParams ?: return null
|
||||
return params.behavior as? ExpandingBottomSheetBehavior<V>
|
||||
}
|
||||
}
|
||||
|
||||
/** [Callback] to notify changes in dragging state and position. */
|
||||
interface Callback {
|
||||
/** Called when the dragging state of the BottomSheet changes. */
|
||||
fun onStateChanged(state: State) {}
|
||||
|
||||
/** Called when the position of the BottomSheet changes while dragging. */
|
||||
fun onSlidePositionChanged(view: View, yPosition: Float) {}
|
||||
}
|
||||
|
||||
/** Represents the 4 possible states of the BottomSheet. */
|
||||
enum class State(val value: Int) {
|
||||
/** BottomSheet is at min height, collapsed at the bottom. */
|
||||
Collapsed(0),
|
||||
|
||||
/** BottomSheet is being dragged by the user. */
|
||||
Dragging(1),
|
||||
|
||||
/** BottomSheet has been released after being dragged by the user and is animating to its destination. */
|
||||
Settling(2),
|
||||
|
||||
/** BottomSheet is at its max height. */
|
||||
Expanded(3);
|
||||
|
||||
/** Returns whether the BottomSheet is being dragged or is settling after being dragged. */
|
||||
fun isDraggingOrSettling(): Boolean = this == Dragging || this == Settling
|
||||
}
|
||||
|
||||
/** Set to true to enable debug logging of sizes and offsets. Defaults to `false`. */
|
||||
var enableDebugLogs = false
|
||||
|
||||
/** Current BottomSheet state. Default to [State.Collapsed]. */
|
||||
var state: State = State.Collapsed
|
||||
private set
|
||||
|
||||
/** Whether the BottomSheet can be dragged by the user or not. Defaults to `true`. */
|
||||
var isDraggable = true
|
||||
|
||||
/** [Callback] to notify changes in dragging state and position. */
|
||||
var callback: Callback? = null
|
||||
set(value) {
|
||||
field = value
|
||||
// Send initial state
|
||||
value?.onStateChanged(state)
|
||||
}
|
||||
|
||||
/** Additional top offset in `dps` to add to the BottomSheet so it doesn't fill the whole screen. Defaults to `0`. */
|
||||
var topOffset = 0
|
||||
set(value) {
|
||||
field = value
|
||||
expandedOffset = -1
|
||||
}
|
||||
|
||||
/** Whether the BottomSheet should be expanded up to the bottom of any [AppBarLayout] found in the parent [CoordinatorLayout]. Defaults to `false`. */
|
||||
var avoidAppBarLayout = false
|
||||
set(value) {
|
||||
field = value
|
||||
expandedOffset = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to add the [scrimView], a 'shadow layer' that will be displayed while dragging/expanded so it obscures the content below the BottomSheet.
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
var useScrimView = false
|
||||
|
||||
/** Color to use for the [scrimView] shadow layer. */
|
||||
var scrimViewColor = 0x60000000
|
||||
|
||||
/** [View.TRANSLATION_Z] in `dps` to apply to the [scrimView]. Defaults to `0dp`. */
|
||||
var scrimViewTranslationZ = 0
|
||||
|
||||
/** Whether the content view should be layout to the top of the BottomSheet when it's collapsed. Defaults to true. */
|
||||
var applyInsetsToContentViewWhenCollapsed = true
|
||||
|
||||
/** Lambda used to calculate a min collapsed when the view using the behavior should have a special 'collapsed' layout. It's null by default. */
|
||||
var minCollapsedHeight: (() -> Int)? = null
|
||||
|
||||
// Internal BottomSheet implementation properties
|
||||
private var ignoreEvents = false
|
||||
private var touchingScrollingChild = false
|
||||
|
||||
private var lastY: Int = -1
|
||||
private var collapsedOffset = -1
|
||||
private var expandedOffset = -1
|
||||
private var parentWidth = -1
|
||||
private var parentHeight = -1
|
||||
|
||||
private var activePointerId = -1
|
||||
|
||||
private var lastNestedScrollDy = -1
|
||||
private var isNestedScrolled = false
|
||||
|
||||
private var viewRef: WeakReference<V>? = null
|
||||
private var nestedScrollingChildRef: WeakReference<View>? = null
|
||||
private var velocityTracker: VelocityTracker? = null
|
||||
|
||||
private var dragHelper: ViewDragHelper? = null
|
||||
private var scrimView: View? = null
|
||||
|
||||
private val stateSettlingTracker = StateSettlingTracker()
|
||||
private var prevState: State? = null
|
||||
|
||||
private var insetBottom = 0
|
||||
private var insetTop = 0
|
||||
private var insetLeft = 0
|
||||
private var insetRight = 0
|
||||
|
||||
private var initialPaddingTop = 0
|
||||
private var initialPaddingBottom = 0
|
||||
private var initialPaddingLeft = 0
|
||||
private var initialPaddingRight = 0
|
||||
private val minCollapsedOffset: Int?
|
||||
get() {
|
||||
val minHeight = minCollapsedHeight?.invoke() ?: return null
|
||||
if (minHeight == -1) return null
|
||||
return parentHeight - minHeight - insetBottom
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor() : super()
|
||||
|
||||
override fun onLayoutChild(parent: CoordinatorLayout, child: V, layoutDirection: Int): Boolean {
|
||||
parentWidth = parent.width
|
||||
parentHeight = parent.height
|
||||
|
||||
if (viewRef == null) {
|
||||
viewRef = WeakReference(child)
|
||||
setWindowInsetsListener(child)
|
||||
// Prevents clicking on overlapped items below the BottomSheet
|
||||
child.isClickable = true
|
||||
}
|
||||
|
||||
parent.updatePadding(left = insetLeft, right = insetRight)
|
||||
|
||||
ensureViewDragHelper(parent)
|
||||
|
||||
// Top coordinate before this layout pass
|
||||
val savedTop = child.top
|
||||
|
||||
// Calculate default position of the BottomSheet's children
|
||||
parent.onLayoutChild(child, layoutDirection)
|
||||
|
||||
// This should optimise calculations when they're not needed
|
||||
if (state == State.Collapsed) {
|
||||
calculateCollapsedOffset(child)
|
||||
}
|
||||
calculateExpandedOffset(parent)
|
||||
|
||||
// Apply top and bottom insets to contentView if needed
|
||||
val appBar = findAppBarLayout(parent)
|
||||
val contentView = parent.children.find { it !== appBar && it !== child && it !== scrimView }
|
||||
if (applyInsetsToContentViewWhenCollapsed && state == State.Collapsed && contentView != null) {
|
||||
val topOffset = appBar?.measuredHeight ?: 0
|
||||
val bottomOffset = parentHeight - collapsedOffset + insetTop
|
||||
val params = contentView.layoutParams as CoordinatorLayout.LayoutParams
|
||||
if (params.bottomMargin != bottomOffset || params.topMargin != topOffset) {
|
||||
params.topMargin = topOffset
|
||||
params.bottomMargin = bottomOffset
|
||||
contentView.layoutParams = params
|
||||
}
|
||||
}
|
||||
|
||||
// Add scrimView if needed
|
||||
if (useScrimView && scrimView == null) {
|
||||
val scrimView = View(parent.context)
|
||||
scrimView.setBackgroundColor(scrimViewColor)
|
||||
scrimView.translationZ = scrimViewTranslationZ * child.resources.displayMetrics.scaledDensity
|
||||
scrimView.isVisible = false
|
||||
val params = CoordinatorLayout.LayoutParams(
|
||||
CoordinatorLayout.LayoutParams.MATCH_PARENT,
|
||||
CoordinatorLayout.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
scrimView.layoutParams = params
|
||||
val currentIndex = parent.children.indexOf(child)
|
||||
parent.addView(scrimView, currentIndex)
|
||||
this.scrimView = scrimView
|
||||
} else if (!useScrimView && scrimView != null) {
|
||||
parent.removeView(scrimView)
|
||||
scrimView = null
|
||||
}
|
||||
|
||||
// Apply insets and resize child based on the current State
|
||||
when (state) {
|
||||
State.Collapsed -> {
|
||||
scrimView?.alpha = 0f
|
||||
val newHeight = parentHeight - collapsedOffset + insetTop
|
||||
val params = child.layoutParams
|
||||
if (params.height != newHeight) {
|
||||
params.height = newHeight
|
||||
child.layoutParams = params
|
||||
}
|
||||
// If the offset is < insetTop it will cover the status bar too
|
||||
val newOffset = max(insetTop, collapsedOffset - insetTop)
|
||||
ViewCompat.offsetTopAndBottom(child, newOffset)
|
||||
log("State: Collapsed | Offset: $newOffset | Height: $newHeight")
|
||||
}
|
||||
State.Dragging, State.Settling -> {
|
||||
val newOffset = savedTop - child.top
|
||||
val percentage = max(0f, 1f - (newOffset.toFloat() / collapsedOffset.toFloat()))
|
||||
scrimView?.let {
|
||||
if (percentage == 0f) {
|
||||
it.isVisible = false
|
||||
} else {
|
||||
it.alpha = percentage
|
||||
it.isVisible = true
|
||||
}
|
||||
}
|
||||
val params = child.layoutParams
|
||||
params.height = parentHeight - savedTop
|
||||
child.layoutParams = params
|
||||
ViewCompat.offsetTopAndBottom(child, newOffset)
|
||||
val stateStr = if (state == State.Dragging) "Dragging" else "Settling"
|
||||
log("State: $stateStr | Offset: $newOffset | Percentage: $percentage")
|
||||
}
|
||||
State.Expanded -> {
|
||||
val params = child.layoutParams
|
||||
val newHeight = parentHeight - expandedOffset
|
||||
if (params.height != newHeight) {
|
||||
params.height = newHeight
|
||||
child.layoutParams = params
|
||||
}
|
||||
ViewCompat.offsetTopAndBottom(child, expandedOffset)
|
||||
log("State: Expanded | Offset: $expandedOffset | Height: $newHeight")
|
||||
}
|
||||
}
|
||||
|
||||
// Find a nested scrolling child to take into account for touch events
|
||||
if (nestedScrollingChildRef == null) {
|
||||
nestedScrollingChildRef = findScrollingChild(child)?.let { WeakReference(it) }
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// region: Touch events
|
||||
override fun onInterceptTouchEvent(
|
||||
parent: CoordinatorLayout,
|
||||
child: V,
|
||||
ev: MotionEvent
|
||||
): Boolean {
|
||||
// Almost everything inside here is verbatim to BottomSheetBehavior's onTouchEvent
|
||||
if (viewRef != null && viewRef?.get() !== child) {
|
||||
return true
|
||||
}
|
||||
val action = ev.actionMasked
|
||||
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
resetTouchEventTracking()
|
||||
}
|
||||
if (velocityTracker == null) {
|
||||
velocityTracker = VelocityTracker.obtain()
|
||||
}
|
||||
velocityTracker?.addMovement(ev)
|
||||
|
||||
when (action) {
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
touchingScrollingChild = false
|
||||
activePointerId = MotionEvent.INVALID_POINTER_ID
|
||||
if (ignoreEvents) {
|
||||
ignoreEvents = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
val x = ev.x.toInt()
|
||||
lastY = ev.y.toInt()
|
||||
|
||||
// Only intercept nested scrolling events here if the view not being moved by the
|
||||
// ViewDragHelper.
|
||||
val scroll = nestedScrollingChildRef?.get()
|
||||
if (state != State.Settling) {
|
||||
if (scroll != null && parent.isPointInChildBounds(scroll, x, lastY)) {
|
||||
activePointerId = ev.getPointerId(ev.actionIndex)
|
||||
touchingScrollingChild = true
|
||||
}
|
||||
}
|
||||
ignoreEvents = (activePointerId == MotionEvent.INVALID_POINTER_ID &&
|
||||
!parent.isPointInChildBounds(child, x, lastY))
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
if (!ignoreEvents && isDraggable && dragHelper?.shouldInterceptTouchEvent(ev) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If using scrim view, a click on it should collapse the bottom sheet
|
||||
if (useScrimView && state == State.Expanded && action == MotionEvent.ACTION_DOWN) {
|
||||
val y = ev.y.toInt()
|
||||
if (y <= expandedOffset) {
|
||||
setState(State.Collapsed)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// We have to handle cases that the ViewDragHelper does not capture the bottom sheet because
|
||||
// it is not the top most view of its parent. This is not necessary when the touch event is
|
||||
// happening over the scrolling content as nested scrolling logic handles that case.
|
||||
val scroll = nestedScrollingChildRef?.get()
|
||||
return (action == MotionEvent.ACTION_MOVE &&
|
||||
scroll != null &&
|
||||
!ignoreEvents &&
|
||||
state != State.Dragging &&
|
||||
!parent.isPointInChildBounds(scroll, ev.x.toInt(), ev.y.toInt()) &&
|
||||
dragHelper != null &&
|
||||
abs(lastY - ev.y.toInt()) > (dragHelper?.touchSlop ?: 0))
|
||||
}
|
||||
|
||||
override fun onTouchEvent(parent: CoordinatorLayout, child: V, ev: MotionEvent): Boolean {
|
||||
// Almost everything inside here is verbatim to BottomSheetBehavior's onTouchEvent
|
||||
val action = ev.actionMasked
|
||||
if (state == State.Dragging && action == MotionEvent.ACTION_DOWN) {
|
||||
return true
|
||||
}
|
||||
if (shouldHandleDraggingWithHelper()) {
|
||||
dragHelper?.processTouchEvent(ev)
|
||||
}
|
||||
|
||||
// Record the velocity
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
resetTouchEventTracking()
|
||||
}
|
||||
if (velocityTracker == null) {
|
||||
velocityTracker = VelocityTracker.obtain()
|
||||
}
|
||||
velocityTracker?.addMovement(ev)
|
||||
|
||||
if (shouldHandleDraggingWithHelper() && action == MotionEvent.ACTION_MOVE && !ignoreEvents) {
|
||||
if (abs(lastY - ev.y.toInt()) > (dragHelper?.touchSlop ?: 0)) {
|
||||
dragHelper?.captureChildView(child, ev.getPointerId(ev.actionIndex))
|
||||
}
|
||||
}
|
||||
|
||||
return !ignoreEvents
|
||||
}
|
||||
|
||||
private fun resetTouchEventTracking() {
|
||||
activePointerId = ViewDragHelper.INVALID_POINTER
|
||||
velocityTracker?.recycle()
|
||||
velocityTracker = null
|
||||
}
|
||||
// endregion
|
||||
|
||||
override fun onAttachedToLayoutParams(params: CoordinatorLayout.LayoutParams) {
|
||||
super.onAttachedToLayoutParams(params)
|
||||
|
||||
viewRef = null
|
||||
dragHelper = null
|
||||
}
|
||||
|
||||
override fun onDetachedFromLayoutParams() {
|
||||
super.onDetachedFromLayoutParams()
|
||||
|
||||
viewRef = null
|
||||
dragHelper = null
|
||||
}
|
||||
|
||||
// region: Size measuring and utils
|
||||
private fun calculateCollapsedOffset(child: View) {
|
||||
val availableSpace = parentHeight - insetTop
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(availableSpace, MeasureSpec.AT_MOST),
|
||||
)
|
||||
collapsedOffset = parentHeight - child.measuredHeight + insetTop
|
||||
}
|
||||
|
||||
private fun calculateExpandedOffset(parent: CoordinatorLayout): Int {
|
||||
expandedOffset = if (avoidAppBarLayout) {
|
||||
findAppBarLayout(parent)?.measuredHeight ?: 0
|
||||
} else {
|
||||
0
|
||||
} + topOffset + insetTop
|
||||
return expandedOffset
|
||||
}
|
||||
|
||||
private fun ensureViewDragHelper(parent: CoordinatorLayout) {
|
||||
if (dragHelper == null) {
|
||||
dragHelper = ViewDragHelper.create(parent, dragHelperCallback)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findAppBarLayout(view: View): AppBarLayout? {
|
||||
return when (view) {
|
||||
is AppBarLayout -> view
|
||||
is ViewGroup -> view.children.firstNotNullOfOrNull { findAppBarLayout(it) }
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldHandleDraggingWithHelper(): Boolean {
|
||||
return dragHelper != null && (isDraggable || state == State.Dragging)
|
||||
}
|
||||
|
||||
private fun log(contents: String, vararg args: Any) {
|
||||
if (!enableDebugLogs) return
|
||||
Timber.d(contents, args)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region: State and delayed state settling
|
||||
fun setState(state: State) {
|
||||
if (state == this.state) {
|
||||
return
|
||||
} else if (viewRef?.get() == null) {
|
||||
setInternalState(state)
|
||||
} else {
|
||||
viewRef?.get()?.let { child ->
|
||||
runAfterLayout(child) { startSettling(child, state, false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setInternalState(state: State) {
|
||||
if (!this.state.isDraggingOrSettling()) {
|
||||
prevState = this.state
|
||||
}
|
||||
this.state = state
|
||||
|
||||
viewRef?.get()?.requestLayout()
|
||||
|
||||
callback?.onStateChanged(state)
|
||||
}
|
||||
|
||||
private fun startSettling(child: View, state: State, isReleasingView: Boolean) {
|
||||
val top = getTopOffsetForState(state)
|
||||
log("Settling to: $top")
|
||||
val isSettling = dragHelper?.let {
|
||||
if (isReleasingView) {
|
||||
it.settleCapturedViewAt(child.left, top)
|
||||
} else {
|
||||
it.smoothSlideViewTo(child, child.left, top)
|
||||
}
|
||||
} ?: false
|
||||
setInternalState(if (isSettling) State.Settling else state)
|
||||
|
||||
if (isSettling) {
|
||||
stateSettlingTracker.continueSettlingToState(state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAfterLayout(child: V, runnable: Runnable) {
|
||||
if (isLayouting(child)) {
|
||||
child.post(runnable)
|
||||
} else {
|
||||
runnable.run()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isLayouting(child: V): Boolean {
|
||||
return child.parent != null && child.parent.isLayoutRequested && ViewCompat.isAttachedToWindow(child)
|
||||
}
|
||||
|
||||
private fun getTopOffsetForState(state: State): Int {
|
||||
return when (state) {
|
||||
State.Collapsed -> minCollapsedOffset ?: collapsedOffset
|
||||
State.Expanded -> expandedOffset
|
||||
else -> error("Cannot get offset for state $state")
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region: Nested scroll
|
||||
override fun onStartNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: V,
|
||||
directTargetChild: View,
|
||||
target: View,
|
||||
axes: Int,
|
||||
type: Int
|
||||
): Boolean {
|
||||
lastNestedScrollDy = 0
|
||||
isNestedScrolled = false
|
||||
return (axes and ViewCompat.SCROLL_AXIS_VERTICAL) != 0
|
||||
}
|
||||
|
||||
override fun onNestedPreScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: V,
|
||||
target: View,
|
||||
dx: Int,
|
||||
dy: Int,
|
||||
consumed: IntArray,
|
||||
type: Int
|
||||
) {
|
||||
if (type == ViewCompat.TYPE_NON_TOUCH) return
|
||||
val scrollingChild = nestedScrollingChildRef?.get()
|
||||
if (target != scrollingChild) return
|
||||
|
||||
val currentTop = child.top
|
||||
val newTop = currentTop - dy
|
||||
if (dy > 0) {
|
||||
// Upward scroll
|
||||
if (newTop < expandedOffset) {
|
||||
consumed[1] = currentTop - expandedOffset
|
||||
ViewCompat.offsetTopAndBottom(child, -consumed[1])
|
||||
setInternalState(State.Expanded)
|
||||
} else {
|
||||
if (!isDraggable) return
|
||||
|
||||
consumed[1] = dy
|
||||
ViewCompat.offsetTopAndBottom(child, -dy)
|
||||
setInternalState(State.Dragging)
|
||||
}
|
||||
} else if (dy < 0) {
|
||||
// Scroll downward
|
||||
if (!target.canScrollVertically(-1)) {
|
||||
if (newTop <= collapsedOffset) {
|
||||
if (!isDraggable) return
|
||||
|
||||
consumed[1] = dy
|
||||
ViewCompat.offsetTopAndBottom(child, -dy)
|
||||
setInternalState(State.Dragging)
|
||||
} else {
|
||||
consumed[1] = currentTop - collapsedOffset
|
||||
ViewCompat.offsetTopAndBottom(child, -consumed[1])
|
||||
setInternalState(State.Collapsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
lastNestedScrollDy = dy
|
||||
isNestedScrolled = true
|
||||
}
|
||||
|
||||
override fun onNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: V,
|
||||
target: View,
|
||||
dxConsumed: Int,
|
||||
dyConsumed: Int,
|
||||
dxUnconsumed: Int,
|
||||
dyUnconsumed: Int,
|
||||
type: Int,
|
||||
consumed: IntArray
|
||||
) {
|
||||
// Empty to avoid default behaviour
|
||||
}
|
||||
|
||||
override fun onNestedPreFling(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: V,
|
||||
target: View,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
): Boolean {
|
||||
return target == nestedScrollingChildRef?.get() &&
|
||||
(state != State.Expanded || super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY))
|
||||
}
|
||||
|
||||
private fun findScrollingChild(view: View): View? {
|
||||
return when {
|
||||
!view.isVisible -> null
|
||||
ViewCompat.isNestedScrollingEnabled(view) -> view
|
||||
view is ViewGroup -> {
|
||||
view.children.firstNotNullOfOrNull { findScrollingChild(it) }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region: Insets
|
||||
private fun setWindowInsetsListener(view: View) {
|
||||
// Create a snapshot of the view's padding state.
|
||||
initialPaddingLeft = view.paddingLeft
|
||||
initialPaddingTop = view.paddingTop
|
||||
initialPaddingRight = view.paddingRight
|
||||
initialPaddingBottom = view.paddingBottom
|
||||
|
||||
// This should only be used to set initial insets and other edge cases where the insets can't be applied using an animation.
|
||||
var applyInsetsFromAnimation = false
|
||||
|
||||
// This will animated inset changes, making them look a lot better. However, it won't update initial insets.
|
||||
ViewCompat.setWindowInsetsAnimationCallback(view, object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
|
||||
override fun onProgress(insets: WindowInsetsCompat, runningAnimations: MutableList<WindowInsetsAnimationCompat>): WindowInsetsCompat {
|
||||
return applyInsets(view, insets)
|
||||
}
|
||||
|
||||
override fun onEnd(animation: WindowInsetsAnimationCompat) {
|
||||
applyInsetsFromAnimation = false
|
||||
view.requestApplyInsets()
|
||||
}
|
||||
})
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { _: View, insets: WindowInsetsCompat ->
|
||||
if (!applyInsetsFromAnimation) {
|
||||
applyInsetsFromAnimation = true
|
||||
applyInsets(view, insets)
|
||||
} else {
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
// Request to apply insets as soon as the view is attached to a window.
|
||||
if (ViewCompat.isAttachedToWindow(view)) {
|
||||
ViewCompat.requestApplyInsets(view)
|
||||
} else {
|
||||
view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View) {
|
||||
v.removeOnAttachStateChangeListener(this)
|
||||
ViewCompat.requestApplyInsets(v)
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(v: View) = Unit
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyInsets(view: View, insets: WindowInsetsCompat): WindowInsetsCompat {
|
||||
val insetsType = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime()
|
||||
val imeInsets = insets.getInsets(insetsType)
|
||||
insetTop = imeInsets.top
|
||||
insetBottom = imeInsets.bottom
|
||||
insetLeft = imeInsets.left
|
||||
insetRight = imeInsets.right
|
||||
|
||||
val bottomPadding = initialPaddingBottom + insetBottom
|
||||
view.setPadding(initialPaddingLeft, initialPaddingTop, initialPaddingRight, bottomPadding)
|
||||
if (state == State.Collapsed) {
|
||||
val params = view.layoutParams
|
||||
params.height = CoordinatorLayout.LayoutParams.WRAP_CONTENT
|
||||
view.layoutParams = params
|
||||
calculateCollapsedOffset(view)
|
||||
}
|
||||
return WindowInsetsCompat.CONSUMED
|
||||
}
|
||||
// endregion
|
||||
|
||||
// Used to add dragging animations along with StateSettlingTracker, and set max and min dragging coordinates.
|
||||
private val dragHelperCallback = object : ViewDragHelper.Callback() {
|
||||
|
||||
override fun tryCaptureView(child: View, pointerId: Int): Boolean {
|
||||
if (state == State.Dragging) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (touchingScrollingChild) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (state == State.Expanded && activePointerId == pointerId) {
|
||||
val scroll = nestedScrollingChildRef?.get()
|
||||
if (scroll?.canScrollVertically(-1) == true) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return viewRef?.get() == child
|
||||
}
|
||||
|
||||
override fun onViewDragStateChanged(state: Int) {
|
||||
if (state == ViewDragHelper.STATE_DRAGGING && isDraggable) {
|
||||
setInternalState(State.Dragging)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewPositionChanged(
|
||||
changedView: View,
|
||||
left: Int,
|
||||
top: Int,
|
||||
dx: Int,
|
||||
dy: Int
|
||||
) {
|
||||
super.onViewPositionChanged(changedView, left, top, dx, dy)
|
||||
|
||||
val params = changedView.layoutParams
|
||||
params.height = parentHeight - top + insetBottom + insetTop
|
||||
changedView.layoutParams = params
|
||||
|
||||
val collapsedOffset = minCollapsedOffset ?: collapsedOffset
|
||||
val percentage = 1f - (top - insetTop).toFloat() / collapsedOffset.toFloat()
|
||||
|
||||
callback?.onSlidePositionChanged(changedView, percentage)
|
||||
}
|
||||
|
||||
override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
|
||||
val actualCollapsedOffset = minCollapsedOffset ?: collapsedOffset
|
||||
val targetState = if (yvel < 0) {
|
||||
// Moving up
|
||||
val currentTop = releasedChild.top
|
||||
|
||||
val yPositionPercentage = currentTop * 100f / actualCollapsedOffset
|
||||
if (yPositionPercentage >= 0.5f) {
|
||||
State.Expanded
|
||||
} else {
|
||||
State.Collapsed
|
||||
}
|
||||
} else if (yvel == 0f || abs(xvel) > abs(yvel)) {
|
||||
// If the Y velocity is 0 or the swipe was mostly horizontal indicated by the X velocity
|
||||
// being greater than the Y velocity, settle to the nearest correct height.
|
||||
|
||||
val currentTop = releasedChild.top
|
||||
if (currentTop < actualCollapsedOffset / 2) {
|
||||
State.Expanded
|
||||
} else {
|
||||
State.Collapsed
|
||||
}
|
||||
} else {
|
||||
// Moving down
|
||||
val currentTop = releasedChild.top
|
||||
|
||||
val yPositionPercentage = currentTop * 100f / actualCollapsedOffset
|
||||
if (yPositionPercentage >= 0.5f) {
|
||||
State.Collapsed
|
||||
} else {
|
||||
State.Expanded
|
||||
}
|
||||
}
|
||||
startSettling(releasedChild, targetState, true)
|
||||
}
|
||||
|
||||
override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {
|
||||
return child.left
|
||||
}
|
||||
|
||||
override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
|
||||
val collapsed = minCollapsedOffset ?: collapsedOffset
|
||||
val maxTop = max(top, insetTop)
|
||||
return min(max(maxTop, expandedOffset), collapsed)
|
||||
}
|
||||
|
||||
override fun getViewVerticalDragRange(child: View): Int {
|
||||
return minCollapsedOffset ?: collapsedOffset
|
||||
}
|
||||
}
|
||||
|
||||
// Used to set the current State in a delayed way.
|
||||
private inner class StateSettlingTracker {
|
||||
private lateinit var targetState: State
|
||||
private var isContinueSettlingRunnablePosted = false
|
||||
|
||||
private val continueSettlingRunnable: Runnable = Runnable {
|
||||
isContinueSettlingRunnablePosted = false
|
||||
if (dragHelper?.continueSettling(true) == true) {
|
||||
continueSettlingToState(targetState)
|
||||
} else {
|
||||
setInternalState(targetState)
|
||||
}
|
||||
}
|
||||
|
||||
fun continueSettlingToState(state: State) {
|
||||
val view = viewRef?.get() ?: return
|
||||
|
||||
this.targetState = state
|
||||
if (!isContinueSettlingRunnablePosted) {
|
||||
ViewCompat.postOnAnimation(view, continueSettlingRunnable)
|
||||
isContinueSettlingRunnablePosted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -34,8 +34,6 @@ class JumpToBottomViewVisibilityManager(
|
||||
private val layoutManager: LinearLayoutManager
|
||||
) {
|
||||
|
||||
private var canShowButtonOnScroll = true
|
||||
|
||||
init {
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
@ -45,7 +43,7 @@ class JumpToBottomViewVisibilityManager(
|
||||
|
||||
if (scrollingToPast) {
|
||||
jumpToBottomView.hide()
|
||||
} else if (canShowButtonOnScroll) {
|
||||
} else {
|
||||
maybeShowJumpToBottomViewVisibility()
|
||||
}
|
||||
}
|
||||
@ -68,13 +66,7 @@ class JumpToBottomViewVisibilityManager(
|
||||
}
|
||||
}
|
||||
|
||||
fun hideAndPreventVisibilityChangesWithScrolling() {
|
||||
jumpToBottomView.hide()
|
||||
canShowButtonOnScroll = false
|
||||
}
|
||||
|
||||
private fun maybeShowJumpToBottomViewVisibility() {
|
||||
canShowButtonOnScroll = true
|
||||
if (layoutManager.findFirstVisibleItemPosition() > 1) {
|
||||
jumpToBottomView.show()
|
||||
} else {
|
||||
|
@ -18,10 +18,12 @@ package im.vector.app.features.home.room.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
@ -98,6 +100,11 @@ class RoomDetailActivity :
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// For dealing with insets and status bar background color
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
|
||||
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
|
||||
waitingView = views.waitingView.waitingView
|
||||
val timelineArgs: TimelineArgs = intent?.extras?.getParcelableCompat(EXTRA_ROOM_DETAIL_ARGS) ?: return
|
||||
|
@ -35,16 +35,17 @@ import android.widget.TextView
|
||||
import androidx.activity.addCallback
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.view.menu.MenuBuilder
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.util.Pair
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
@ -67,7 +68,6 @@ import im.vector.app.core.dialogs.ConfirmationDialogBuilder
|
||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelperFactory
|
||||
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
||||
import im.vector.app.core.extensions.animateLayoutChange
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.extensions.containsRtLOverride
|
||||
@ -187,9 +187,7 @@ import im.vector.app.features.widgets.WidgetArgs
|
||||
import im.vector.app.features.widgets.WidgetKind
|
||||
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -418,20 +416,12 @@ class TimelineFragment :
|
||||
}
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
handleSpaceShare()
|
||||
ViewCompat.setOnApplyWindowInsetsListener(views.coordinatorLayout) { _, insets ->
|
||||
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime() or WindowInsetsCompat.Type.systemBars())
|
||||
views.appBarLayout.updatePadding(top = imeInsets.top)
|
||||
views.voiceMessageRecorderContainer.updatePadding(bottom = imeInsets.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
views.scrim.setOnClickListener {
|
||||
messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(false))
|
||||
}
|
||||
|
||||
messageComposerViewModel.stateFlow.map { it.isFullScreen }
|
||||
.distinctUntilChanged()
|
||||
.onEach { isFullScreen ->
|
||||
toggleFullScreenEditor(isFullScreen)
|
||||
}
|
||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||
}
|
||||
|
||||
private fun setupBackPressHandling() {
|
||||
@ -1048,13 +1038,7 @@ class TimelineFragment :
|
||||
override fun onLayoutCompleted(state: RecyclerView.State) {
|
||||
super.onLayoutCompleted(state)
|
||||
updateJumpToReadMarkerViewVisibility()
|
||||
withState(messageComposerViewModel) { composerState ->
|
||||
if (!composerState.isFullScreen) {
|
||||
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
|
||||
} else {
|
||||
jumpToBottomViewVisibilityManager.hideAndPreventVisibilityChangesWithScrolling()
|
||||
}
|
||||
}
|
||||
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
|
||||
}
|
||||
}.apply {
|
||||
// For local rooms, pin the view's content to the top edge (the layout is reversed)
|
||||
@ -1170,7 +1154,6 @@ class TimelineFragment :
|
||||
if (mainState.tombstoneEvent == null) {
|
||||
views.composerContainer.isInvisible = !messageComposerState.isComposerVisible
|
||||
views.voiceMessageRecorderContainer.isVisible = messageComposerState.isVoiceMessageRecorderVisible
|
||||
|
||||
when (messageComposerState.canSendMessage) {
|
||||
CanSendStatus.Allowed -> {
|
||||
NotificationAreaView.State.Hidden
|
||||
@ -2036,19 +2019,6 @@ class TimelineFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleFullScreenEditor(isFullScreen: Boolean) {
|
||||
views.composerContainer.animateLayoutChange(200)
|
||||
|
||||
val constraintSet = ConstraintSet()
|
||||
val constraintSetId = if (isFullScreen) {
|
||||
R.layout.fragment_timeline_fullscreen
|
||||
} else {
|
||||
R.layout.fragment_timeline
|
||||
}
|
||||
constraintSet.clone(requireContext(), constraintSetId)
|
||||
constraintSet.applyTo(views.rootConstraintLayout)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current room is a Thread room, false otherwise.
|
||||
*/
|
||||
|
@ -33,7 +33,6 @@ sealed class MessageComposerAction : VectorViewModelAction {
|
||||
data class OnEntersBackground(val composerText: String) : MessageComposerAction()
|
||||
data class SlashCommandConfirmed(val parsedCommand: ParsedCommand) : MessageComposerAction()
|
||||
data class InsertUserDisplayName(val userId: String) : MessageComposerAction()
|
||||
|
||||
data class SetFullScreen(val isFullScreen: Boolean) : MessageComposerAction()
|
||||
|
||||
// Voice Message
|
||||
|
@ -24,7 +24,6 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Spannable
|
||||
import android.text.format.DateUtils
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -32,10 +31,7 @@ import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
@ -51,7 +47,6 @@ import com.vanniktech.emoji.EmojiPopup
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.error.fatalError
|
||||
import im.vector.app.core.extensions.getVectorLastMessageContent
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.showKeyboard
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
@ -59,7 +54,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.platform.lifecycleAwareLazy
|
||||
import im.vector.app.core.platform.showOptimizedSnackbar
|
||||
import im.vector.app.core.resources.BuildMeta
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.core.utils.ExpandingBottomSheetBehavior
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.onPermissionDeniedDialog
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
@ -86,14 +81,9 @@ import im.vector.app.features.home.room.detail.RoomDetailAction.VoiceBroadcastAc
|
||||
import im.vector.app.features.home.room.detail.TimelineViewModel
|
||||
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
|
||||
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
||||
import im.vector.app.features.home.room.detail.timeline.image.buildImageContentRendererData
|
||||
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
import im.vector.app.features.html.PillImageSpan
|
||||
import im.vector.app.features.html.PillsPostProcessor
|
||||
import im.vector.app.features.location.LocationSharingMode
|
||||
import im.vector.app.features.media.ImageContentRenderer
|
||||
import im.vector.app.features.poll.PollMode
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.share.SharedData
|
||||
@ -104,18 +94,9 @@ import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.commonmark.parser.Parser
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import reactivecircus.flowbinding.android.view.focusChanges
|
||||
import reactivecircus.flowbinding.android.widget.textChanges
|
||||
import timber.log.Timber
|
||||
@ -130,12 +111,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
|
||||
@Inject lateinit var autoCompleterFactory: AutoCompleter.Factory
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
@Inject lateinit var matrixItemColorProvider: MatrixItemColorProvider
|
||||
@Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
|
||||
@Inject lateinit var dimensionConverter: DimensionConverter
|
||||
@Inject lateinit var imageContentRenderer: ImageContentRenderer
|
||||
@Inject lateinit var shareIntentHandler: ShareIntentHandler
|
||||
@Inject lateinit var pillsPostProcessorFactory: PillsPostProcessor.Factory
|
||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||
@Inject lateinit var vectorFeatures: VectorFeatures
|
||||
@Inject lateinit var buildMeta: BuildMeta
|
||||
@ -147,10 +123,6 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
autoCompleterFactory.create(roomId, isThreadTimeLine())
|
||||
}
|
||||
|
||||
private val pillsPostProcessor by lazy {
|
||||
pillsPostProcessorFactory.create(roomId)
|
||||
}
|
||||
|
||||
private val emojiPopup: EmojiPopup by lifecycleAwareLazy {
|
||||
createEmojiPopup()
|
||||
}
|
||||
@ -166,6 +138,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
|
||||
private lateinit var attachmentsHelper: AttachmentsHelper
|
||||
private lateinit var attachmentTypeSelector: AttachmentTypeSelectorView
|
||||
private var bottomSheetBehavior: ExpandingBottomSheetBehavior<View>? = null
|
||||
|
||||
private val timelineViewModel: TimelineViewModel by parentFragmentViewModel()
|
||||
private val messageComposerViewModel: MessageComposerViewModel by parentFragmentViewModel()
|
||||
@ -192,6 +165,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
|
||||
attachmentsHelper = AttachmentsHelper(requireContext(), this, buildMeta).register()
|
||||
|
||||
setupBottomSheet()
|
||||
setupComposer()
|
||||
setupEmojiButton()
|
||||
|
||||
@ -217,22 +191,15 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
}
|
||||
}
|
||||
|
||||
messageComposerViewModel.stateFlow.map { it.isFullScreen }
|
||||
.distinctUntilChanged()
|
||||
.onEach { isFullScreen ->
|
||||
composer.toggleFullScreen(isFullScreen)
|
||||
}
|
||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||
|
||||
messageComposerViewModel.onEach(MessageComposerViewState::sendMode, MessageComposerViewState::canSendMessage) { mode, canSend ->
|
||||
if (!canSend.boolean()) {
|
||||
return@onEach
|
||||
}
|
||||
when (mode) {
|
||||
is SendMode.Regular -> renderRegularMode(mode.text.toString())
|
||||
is SendMode.Edit -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_edit, R.string.edit, mode.text.toString())
|
||||
is SendMode.Quote -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_quote, R.string.action_quote, mode.text.toString())
|
||||
is SendMode.Reply -> renderSpecialMode(mode.timelineEvent, R.drawable.ic_reply, R.string.reply, mode.text.toString())
|
||||
is SendMode.Edit -> renderSpecialMode(MessageComposerMode.Edit(mode.timelineEvent, mode.text.toString()))
|
||||
is SendMode.Quote -> renderSpecialMode(MessageComposerMode.Quote(mode.timelineEvent, mode.text.toString()))
|
||||
is SendMode.Reply -> renderSpecialMode(MessageComposerMode.Reply(mode.timelineEvent, mode.text.toString()))
|
||||
is SendMode.Voice -> renderVoiceMessageMode(mode.text)
|
||||
}
|
||||
}
|
||||
@ -242,6 +209,14 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
.onEach { onTypeSelected(it.attachmentType) }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
messageComposerViewModel.stateFlow.map { it.isFullScreen }
|
||||
.distinctUntilChanged()
|
||||
.onEach { isFullScreen ->
|
||||
val state = if (isFullScreen) ExpandingBottomSheetBehavior.State.Expanded else ExpandingBottomSheetBehavior.State.Collapsed
|
||||
bottomSheetBehavior?.setState(state)
|
||||
}
|
||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
handleShareData()
|
||||
}
|
||||
@ -280,11 +255,45 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
) { mainState, messageComposerState, attachmentState ->
|
||||
if (mainState.tombstoneEvent != null) return@withState
|
||||
|
||||
composer.setInvisible(!messageComposerState.isComposerVisible)
|
||||
(composer as? View)?.isInvisible = !messageComposerState.isComposerVisible
|
||||
composer.sendButton.isInvisible = !messageComposerState.isSendButtonVisible
|
||||
(composer as? RichTextComposerLayout)?.isTextFormattingEnabled = attachmentState.isTextFormattingEnabled
|
||||
}
|
||||
|
||||
private fun setupBottomSheet() {
|
||||
val parentView = view?.parent as? View ?: return
|
||||
bottomSheetBehavior = ExpandingBottomSheetBehavior.from(parentView)?.apply {
|
||||
applyInsetsToContentViewWhenCollapsed = true
|
||||
topOffset = 22
|
||||
useScrimView = true
|
||||
scrimViewTranslationZ = 8
|
||||
minCollapsedHeight = {
|
||||
(composer as? RichTextComposerLayout)?.estimateCollapsedHeight() ?: -1
|
||||
}
|
||||
isDraggable = false
|
||||
callback = object : ExpandingBottomSheetBehavior.Callback {
|
||||
override fun onStateChanged(state: ExpandingBottomSheetBehavior.State) {
|
||||
// Dragging is disabled while the composer is collapsed
|
||||
bottomSheetBehavior?.isDraggable = state != ExpandingBottomSheetBehavior.State.Collapsed
|
||||
|
||||
val setFullScreen = when (state) {
|
||||
ExpandingBottomSheetBehavior.State.Collapsed -> false
|
||||
ExpandingBottomSheetBehavior.State.Expanded -> true
|
||||
else -> return
|
||||
}
|
||||
|
||||
(composer as? RichTextComposerLayout)?.setFullScreen(setFullScreen)
|
||||
|
||||
messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(setFullScreen))
|
||||
}
|
||||
|
||||
override fun onSlidePositionChanged(view: View, yPosition: Float) {
|
||||
(composer as? RichTextComposerLayout)?.notifyIsBeingDragged(yPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupComposer() {
|
||||
val composerEditText = composer.editText
|
||||
composerEditText.setHint(R.string.room_message_placeholder)
|
||||
@ -382,8 +391,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
return
|
||||
}
|
||||
if (text.isNotBlank()) {
|
||||
// We collapse ASAP, if not there will be a slight annoying delay
|
||||
composer.collapse(true)
|
||||
composer.renderComposerMode(MessageComposerMode.Normal(""))
|
||||
lockSendButton = true
|
||||
if (formattedText != null) {
|
||||
messageComposerViewModel.handle(MessageComposerAction.SendMessage(text, formattedText, false))
|
||||
@ -407,66 +415,12 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
|
||||
private fun renderRegularMode(content: CharSequence) {
|
||||
autoCompleter.exitSpecialMode()
|
||||
composer.collapse()
|
||||
composer.setTextIfDifferent(content)
|
||||
composer.sendButton.contentDescription = getString(R.string.action_send)
|
||||
composer.renderComposerMode(MessageComposerMode.Normal(content))
|
||||
}
|
||||
|
||||
private fun renderSpecialMode(
|
||||
event: TimelineEvent,
|
||||
@DrawableRes iconRes: Int,
|
||||
@StringRes descriptionRes: Int,
|
||||
defaultContent: CharSequence,
|
||||
) {
|
||||
private fun renderSpecialMode(mode: MessageComposerMode.Special) {
|
||||
autoCompleter.enterSpecialMode()
|
||||
// switch to expanded bar
|
||||
composer.composerRelatedMessageTitle.apply {
|
||||
text = event.senderInfo.disambiguatedDisplayName
|
||||
setTextColor(matrixItemColorProvider.getColor(MatrixItem.UserItem(event.root.senderId ?: "@")))
|
||||
}
|
||||
|
||||
val messageContent: MessageContent? = event.getVectorLastMessageContent()
|
||||
val nonFormattedBody = when (messageContent) {
|
||||
is MessageAudioContent -> getAudioContentBodyText(messageContent)
|
||||
is MessagePollContent -> messageContent.getBestPollCreationInfo()?.question?.getBestQuestion()
|
||||
is MessageBeaconInfoContent -> getString(R.string.live_location_description)
|
||||
else -> messageContent?.body.orEmpty()
|
||||
}
|
||||
var formattedBody: CharSequence? = null
|
||||
if (messageContent is MessageTextContent && messageContent.format == MessageFormat.FORMAT_MATRIX_HTML) {
|
||||
val parser = Parser.builder().build()
|
||||
val document = parser.parse(messageContent.formattedBody ?: messageContent.body)
|
||||
formattedBody = eventHtmlRenderer.render(document, pillsPostProcessor)
|
||||
}
|
||||
composer.composerRelatedMessageContent.text = (formattedBody ?: nonFormattedBody)
|
||||
|
||||
// Image Event
|
||||
val data = event.buildImageContentRendererData(dimensionConverter.dpToPx(66))
|
||||
val isImageVisible = if (data != null) {
|
||||
imageContentRenderer.render(data, ImageContentRenderer.Mode.THUMBNAIL, composer.composerRelatedMessageImage)
|
||||
true
|
||||
} else {
|
||||
imageContentRenderer.clear(composer.composerRelatedMessageImage)
|
||||
false
|
||||
}
|
||||
|
||||
composer.composerRelatedMessageImage.isVisible = isImageVisible
|
||||
|
||||
composer.replaceFormattedContent(defaultContent)
|
||||
|
||||
composer.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes))
|
||||
composer.sendButton.contentDescription = getString(descriptionRes)
|
||||
|
||||
avatarRenderer.render(event.senderInfo.toMatrixItem(), composer.composerRelatedMessageAvatar)
|
||||
|
||||
composer.expand {
|
||||
if (isAdded) {
|
||||
// need to do it here also when not using quick reply
|
||||
focusComposerAndShowKeyboard()
|
||||
composer.composerRelatedMessageImage.isVisible = isImageVisible
|
||||
}
|
||||
}
|
||||
focusComposerAndShowKeyboard()
|
||||
composer.renderComposerMode(mode)
|
||||
}
|
||||
|
||||
private fun observerUserTyping() {
|
||||
@ -489,7 +443,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
}
|
||||
|
||||
private fun focusComposerAndShowKeyboard() {
|
||||
if (composer.isVisible) {
|
||||
if ((composer as? View)?.isVisible == true) {
|
||||
composer.editText.showKeyboard(andRequestFocus = true)
|
||||
}
|
||||
}
|
||||
@ -499,7 +453,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
composer.sendButton.alpha = 0f
|
||||
composer.sendButton.isVisible = true
|
||||
composer.sendButton.animate().alpha(1f).setDuration(150).start()
|
||||
} else if (!event.isVisible) {
|
||||
} else {
|
||||
composer.sendButton.isInvisible = true
|
||||
}
|
||||
}
|
||||
@ -510,15 +464,6 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAudioContentBodyText(messageContent: MessageAudioContent): String {
|
||||
val formattedDuration = DateUtils.formatElapsedTime(((messageContent.audioInfo?.duration ?: 0) / 1000).toLong())
|
||||
return if (messageContent.voiceMessageIndicator != null) {
|
||||
getString(R.string.voice_message_reply_content, formattedDuration)
|
||||
} else {
|
||||
getString(R.string.audio_message_reply_content, messageContent.body, formattedDuration)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEmojiPopup(): EmojiPopup {
|
||||
return EmojiPopup(
|
||||
rootView = views.root,
|
||||
@ -840,11 +785,6 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||
return displayName
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root thread event if we are in a thread room, otherwise returns null.
|
||||
*/
|
||||
fun getRootThreadEventId(): String? = withState(timelineViewModel) { it.rootThreadEventId }
|
||||
|
||||
/**
|
||||
* Returns true if the current room is a Thread room, false otherwise.
|
||||
*/
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 im.vector.app.features.home.room.detail.composer
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
|
||||
sealed interface MessageComposerMode {
|
||||
data class Normal(val content: CharSequence?) : MessageComposerMode
|
||||
|
||||
sealed class Special(open val event: TimelineEvent, open val defaultContent: CharSequence) : MessageComposerMode
|
||||
data class Edit(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
||||
class Quote(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
||||
class Reply(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
||||
}
|
@ -19,35 +19,24 @@ package im.vector.app.features.home.room.detail.composer
|
||||
import android.text.Editable
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
interface MessageComposerView {
|
||||
|
||||
companion object {
|
||||
const val MAX_LINES_WHEN_COLLAPSED = 10
|
||||
}
|
||||
|
||||
val text: Editable?
|
||||
val formattedText: String?
|
||||
val editText: EditText
|
||||
val emojiButton: ImageButton?
|
||||
val sendButton: 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 isVisible: Boolean
|
||||
|
||||
fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null)
|
||||
fun expand(animate: Boolean = true, transitionComplete: (() -> Unit)? = null)
|
||||
fun setTextIfDifferent(text: CharSequence?): Boolean
|
||||
fun replaceFormattedContent(text: CharSequence)
|
||||
fun toggleFullScreen(newValue: Boolean)
|
||||
|
||||
fun setInvisible(isInvisible: Boolean)
|
||||
fun renderComposerMode(mode: MessageComposerMode)
|
||||
}
|
||||
|
||||
interface Callback : ComposerEditText.Callback {
|
||||
|
@ -19,44 +19,59 @@ package im.vector.app.features.home.room.detail.composer
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.text.Editable
|
||||
import android.text.format.DateUtils
|
||||
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 android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.Fade
|
||||
import androidx.transition.Transition
|
||||
import androidx.transition.TransitionManager
|
||||
import androidx.transition.TransitionSet
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.animations.SimpleTransitionListener
|
||||
import im.vector.app.core.extensions.getVectorLastMessageContent
|
||||
import im.vector.app.core.extensions.setTextIfDifferent
|
||||
import im.vector.app.core.extensions.showKeyboard
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.databinding.ComposerLayoutBinding
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
|
||||
import im.vector.app.features.home.room.detail.timeline.image.buildImageContentRendererData
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
import im.vector.app.features.html.PillsPostProcessor
|
||||
import im.vector.app.features.media.ImageContentRenderer
|
||||
import org.commonmark.parser.Parser
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Encapsulate the timeline composer UX.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class PlainTextComposerLayout @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr), MessageComposerView {
|
||||
) : LinearLayout(context, attrs, defStyleAttr), MessageComposerView {
|
||||
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
@Inject lateinit var matrixItemColorProvider: MatrixItemColorProvider
|
||||
@Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
|
||||
@Inject lateinit var dimensionConverter: DimensionConverter
|
||||
@Inject lateinit var imageContentRenderer: ImageContentRenderer
|
||||
@Inject lateinit var pillsPostProcessorFactory: PillsPostProcessor.Factory
|
||||
|
||||
private val views: ComposerLayoutBinding
|
||||
|
||||
override var callback: Callback? = null
|
||||
|
||||
private var currentConstraintSetId: Int = -1
|
||||
|
||||
private val animationDuration = 100L
|
||||
|
||||
override val text: Editable?
|
||||
get() = views.composerEditText.text
|
||||
|
||||
@ -65,37 +80,23 @@ class PlainTextComposerLayout @JvmOverloads constructor(
|
||||
override val editText: EditText
|
||||
get() = views.composerEditText
|
||||
|
||||
@Suppress("RedundantNullableReturnType")
|
||||
override val emojiButton: ImageButton?
|
||||
get() = views.composerEmojiButton
|
||||
|
||||
override val sendButton: ImageButton
|
||||
get() = views.sendButton
|
||||
|
||||
override fun setInvisible(isInvisible: Boolean) {
|
||||
this.isInvisible = isInvisible
|
||||
}
|
||||
override val attachmentButton: ImageButton
|
||||
get() = views.attachmentButton
|
||||
override val fullScreenButton: ImageButton? = null
|
||||
override val composerRelatedMessageActionIcon: ImageView
|
||||
get() = views.composerRelatedMessageActionIcon
|
||||
override val composerRelatedMessageAvatar: ImageView
|
||||
get() = views.composerRelatedMessageAvatar
|
||||
override val composerRelatedMessageContent: TextView
|
||||
get() = views.composerRelatedMessageContent
|
||||
override val composerRelatedMessageImage: ImageView
|
||||
get() = views.composerRelatedMessageImage
|
||||
override val composerRelatedMessageTitle: TextView
|
||||
get() = views.composerRelatedMessageTitle
|
||||
override var isVisible: Boolean
|
||||
get() = views.root.isVisible
|
||||
set(value) { views.root.isVisible = value }
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.composer_layout, this)
|
||||
views = ComposerLayoutBinding.bind(this)
|
||||
|
||||
collapse(false)
|
||||
views.composerEditText.maxLines = MessageComposerView.MAX_LINES_WHEN_COLLAPSED
|
||||
|
||||
collapse()
|
||||
|
||||
views.composerEditText.callback = object : ComposerEditText.Callback {
|
||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||
@ -121,27 +122,15 @@ class PlainTextComposerLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun replaceFormattedContent(text: CharSequence) {
|
||||
setTextIfDifferent(text)
|
||||
}
|
||||
|
||||
override fun collapse(animate: Boolean, transitionComplete: (() -> Unit)?) {
|
||||
if (currentConstraintSetId == R.layout.composer_layout_constraint_set_compact) {
|
||||
// ignore we good
|
||||
return
|
||||
}
|
||||
currentConstraintSetId = R.layout.composer_layout_constraint_set_compact
|
||||
applyNewConstraintSet(animate, transitionComplete)
|
||||
private fun collapse(transitionComplete: (() -> Unit)? = null) {
|
||||
views.relatedMessageGroup.isVisible = false
|
||||
transitionComplete?.invoke()
|
||||
callback?.onExpandOrCompactChange()
|
||||
}
|
||||
|
||||
override fun expand(animate: Boolean, transitionComplete: (() -> Unit)?) {
|
||||
if (currentConstraintSetId == R.layout.composer_layout_constraint_set_expanded) {
|
||||
// ignore we good
|
||||
return
|
||||
}
|
||||
currentConstraintSetId = R.layout.composer_layout_constraint_set_expanded
|
||||
applyNewConstraintSet(animate, transitionComplete)
|
||||
private fun expand(transitionComplete: (() -> Unit)? = null) {
|
||||
views.relatedMessageGroup.isVisible = true
|
||||
transitionComplete?.invoke()
|
||||
callback?.onExpandOrCompactChange()
|
||||
}
|
||||
|
||||
@ -149,35 +138,92 @@ class PlainTextComposerLayout @JvmOverloads constructor(
|
||||
return views.composerEditText.setTextIfDifferent(text)
|
||||
}
|
||||
|
||||
override fun toggleFullScreen(newValue: Boolean) {
|
||||
// Plain text composer has no full screen
|
||||
override fun renderComposerMode(mode: MessageComposerMode) {
|
||||
val specialMode = mode as? MessageComposerMode.Special
|
||||
if (specialMode != null) {
|
||||
renderSpecialMode(specialMode)
|
||||
} else if (mode is MessageComposerMode.Normal) {
|
||||
collapse()
|
||||
editText.setTextIfDifferent(mode.content)
|
||||
}
|
||||
|
||||
views.sendButton.apply {
|
||||
if (mode is MessageComposerMode.Edit) {
|
||||
contentDescription = resources.getString(R.string.action_save)
|
||||
setImageResource(R.drawable.ic_composer_rich_text_save)
|
||||
} else {
|
||||
contentDescription = resources.getString(R.string.action_send)
|
||||
setImageResource(R.drawable.ic_rich_composer_send)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyNewConstraintSet(animate: Boolean, transitionComplete: (() -> Unit)?) {
|
||||
// val wasSendButtonInvisible = views.sendButton.isInvisible
|
||||
if (animate) {
|
||||
configureAndBeginTransition(transitionComplete)
|
||||
private fun renderSpecialMode(specialMode: MessageComposerMode.Special) {
|
||||
val event = specialMode.event
|
||||
val defaultContent = specialMode.defaultContent
|
||||
|
||||
val iconRes: Int = when (specialMode) {
|
||||
is MessageComposerMode.Reply -> R.drawable.ic_reply
|
||||
is MessageComposerMode.Edit -> R.drawable.ic_edit
|
||||
is MessageComposerMode.Quote -> R.drawable.ic_quote
|
||||
}
|
||||
ConstraintSet().also {
|
||||
it.clone(context, currentConstraintSetId)
|
||||
it.applyTo(this)
|
||||
|
||||
val pillsPostProcessor = pillsPostProcessorFactory.create(event.roomId)
|
||||
|
||||
// switch to expanded bar
|
||||
views.composerRelatedMessageTitle.apply {
|
||||
text = event.senderInfo.disambiguatedDisplayName
|
||||
setTextColor(matrixItemColorProvider.getColor(MatrixItem.UserItem(event.root.senderId ?: "@")))
|
||||
}
|
||||
|
||||
val messageContent: MessageContent? = event.getVectorLastMessageContent()
|
||||
val nonFormattedBody = when (messageContent) {
|
||||
is MessageAudioContent -> getAudioContentBodyText(messageContent)
|
||||
is MessagePollContent -> messageContent.getBestPollCreationInfo()?.question?.getBestQuestion()
|
||||
is MessageBeaconInfoContent -> resources.getString(R.string.live_location_description)
|
||||
else -> messageContent?.body.orEmpty()
|
||||
}
|
||||
var formattedBody: CharSequence? = null
|
||||
if (messageContent is MessageTextContent && messageContent.format == MessageFormat.FORMAT_MATRIX_HTML) {
|
||||
val parser = Parser.builder().build()
|
||||
val document = parser.parse(messageContent.formattedBody ?: messageContent.body)
|
||||
formattedBody = eventHtmlRenderer.render(document, pillsPostProcessor)
|
||||
}
|
||||
views.composerRelatedMessageContent.text = (formattedBody ?: nonFormattedBody)
|
||||
|
||||
// Image Event
|
||||
val data = event.buildImageContentRendererData(dimensionConverter.dpToPx(66))
|
||||
val isImageVisible = if (data != null) {
|
||||
imageContentRenderer.render(data, ImageContentRenderer.Mode.THUMBNAIL, views.composerRelatedMessageImage)
|
||||
true
|
||||
} else {
|
||||
imageContentRenderer.clear(views.composerRelatedMessageImage)
|
||||
false
|
||||
}
|
||||
|
||||
views.composerRelatedMessageImage.isVisible = isImageVisible
|
||||
|
||||
views.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(context, iconRes))
|
||||
|
||||
avatarRenderer.render(event.senderInfo.toMatrixItem(), views.composerRelatedMessageAvatar)
|
||||
|
||||
views.composerEditText.setText(defaultContent)
|
||||
|
||||
expand {
|
||||
// need to do it here also when not using quick reply
|
||||
if (isVisible) {
|
||||
showKeyboard(andRequestFocus = true)
|
||||
}
|
||||
views.composerRelatedMessageImage.isVisible = isImageVisible
|
||||
}
|
||||
// Might be updated by view state just after, but avoid blinks
|
||||
// views.sendButton.isInvisible = wasSendButtonInvisible
|
||||
}
|
||||
|
||||
private fun configureAndBeginTransition(transitionComplete: (() -> Unit)? = null) {
|
||||
val transition = TransitionSet().apply {
|
||||
ordering = TransitionSet.ORDERING_SEQUENTIAL
|
||||
addTransition(ChangeBounds())
|
||||
addTransition(Fade(Fade.IN))
|
||||
duration = animationDuration
|
||||
addListener(object : SimpleTransitionListener() {
|
||||
override fun onTransitionEnd(transition: Transition) {
|
||||
transitionComplete?.invoke()
|
||||
}
|
||||
})
|
||||
private fun getAudioContentBodyText(messageContent: MessageAudioContent): String {
|
||||
val formattedDuration = DateUtils.formatElapsedTime(((messageContent.audioInfo?.duration ?: 0) / 1000).toLong())
|
||||
return if (messageContent.voiceMessageIndicator != null) {
|
||||
resources.getString(R.string.voice_message_reply_content, formattedDuration)
|
||||
} else {
|
||||
resources.getString(R.string.audio_message_reply_content, messageContent.body, formattedDuration)
|
||||
}
|
||||
TransitionManager.beginDelayedTransition((parent as? ViewGroup ?: this), transition)
|
||||
}
|
||||
}
|
||||
|
@ -16,25 +16,34 @@
|
||||
|
||||
package im.vector.app.features.home.room.detail.composer
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
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.TextWatcher
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.animateLayoutChange
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.setTextIfDifferent
|
||||
import im.vector.app.core.extensions.showKeyboard
|
||||
import im.vector.app.databinding.ComposerRichTextLayoutBinding
|
||||
import im.vector.app.databinding.ViewRichTextMenuButtonBinding
|
||||
import io.element.android.wysiwyg.EditorEditText
|
||||
@ -46,23 +55,22 @@ class RichTextComposerLayout @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr), MessageComposerView {
|
||||
) : LinearLayout(context, attrs, defStyleAttr), MessageComposerView {
|
||||
|
||||
private val views: ComposerRichTextLayoutBinding
|
||||
|
||||
override var callback: Callback? = null
|
||||
|
||||
private var currentConstraintSetId: Int = -1
|
||||
private val animationDuration = 100L
|
||||
private val maxEditTextLinesWhenCollapsed = 12
|
||||
|
||||
private val isFullScreen: Boolean get() = currentConstraintSetId == R.layout.composer_rich_text_layout_constraint_set_fullscreen
|
||||
// There is no need to persist these values since they're always updated by the parent fragment
|
||||
private var isFullScreen = false
|
||||
private var hasRelatedMessage = false
|
||||
|
||||
var isTextFormattingEnabled = true
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
syncEditTexts()
|
||||
field = value
|
||||
updateTextFieldBorder(isFullScreen)
|
||||
updateEditTextVisibility()
|
||||
}
|
||||
|
||||
@ -82,37 +90,94 @@ class RichTextComposerLayout @JvmOverloads constructor(
|
||||
get() = views.sendButton
|
||||
override val attachmentButton: ImageButton
|
||||
get() = views.attachmentButton
|
||||
override val fullScreenButton: ImageButton?
|
||||
get() = views.composerFullScreenButton
|
||||
override val composerRelatedMessageActionIcon: ImageView
|
||||
get() = views.composerRelatedMessageActionIcon
|
||||
override val composerRelatedMessageAvatar: ImageView
|
||||
get() = views.composerRelatedMessageAvatar
|
||||
override val composerRelatedMessageContent: TextView
|
||||
get() = views.composerRelatedMessageContent
|
||||
override val composerRelatedMessageImage: ImageView
|
||||
get() = views.composerRelatedMessageImage
|
||||
override val composerRelatedMessageTitle: TextView
|
||||
get() = views.composerRelatedMessageTitle
|
||||
override var isVisible: Boolean
|
||||
get() = views.root.isVisible
|
||||
set(value) { views.root.isVisible = value }
|
||||
|
||||
// Border of the EditText
|
||||
private val borderShapeDrawable: MaterialShapeDrawable by lazy {
|
||||
MaterialShapeDrawable().apply {
|
||||
val typedData = TypedValue()
|
||||
val lineColor = context.theme.obtainStyledAttributes(typedData.data, intArrayOf(R.attr.vctr_content_quaternary))
|
||||
.getColor(0, 0)
|
||||
strokeColor = ColorStateList.valueOf(lineColor)
|
||||
strokeWidth = 1 * resources.displayMetrics.scaledDensity
|
||||
fillColor = ColorStateList.valueOf(Color.TRANSPARENT)
|
||||
val cornerSize = resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_single_line)
|
||||
setCornerSize(cornerSize.toFloat())
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
inflate(context, R.layout.composer_rich_text_layout, 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(
|
||||
TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder() })
|
||||
TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder(isFullScreen) })
|
||||
)
|
||||
views.plainTextComposerEditText.addTextChangedListener(
|
||||
TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder() })
|
||||
TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder(isFullScreen) })
|
||||
)
|
||||
|
||||
views.composerRelatedMessageCloseButton.setOnClickListener {
|
||||
collapse()
|
||||
disallowParentInterceptTouchEvent(views.richTextComposerEditText)
|
||||
disallowParentInterceptTouchEvent(views.plainTextComposerEditText)
|
||||
|
||||
views.composerModeCloseView.setOnClickListener {
|
||||
callback?.onCloseRelatedMessage()
|
||||
}
|
||||
|
||||
@ -125,11 +190,19 @@ class RichTextComposerLayout @JvmOverloads constructor(
|
||||
callback?.onAddAttachment()
|
||||
}
|
||||
|
||||
views.composerFullScreenButton.setOnClickListener {
|
||||
callback?.onFullScreenModeChanged()
|
||||
views.composerFullScreenButton.apply {
|
||||
// There's no point in having full screen in landscape since there's almost no vertical space
|
||||
isInvisible = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
setOnClickListener {
|
||||
callback?.onFullScreenModeChanged()
|
||||
}
|
||||
}
|
||||
|
||||
views.composerEditTextOuterBorder.background = borderShapeDrawable
|
||||
|
||||
setupRichTextMenu()
|
||||
|
||||
updateTextFieldBorder(isFullScreen)
|
||||
}
|
||||
|
||||
private fun setupRichTextMenu() {
|
||||
@ -147,6 +220,21 @@ class RichTextComposerLayout @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
super.onAttachedToWindow()
|
||||
|
||||
@ -197,84 +285,99 @@ class RichTextComposerLayout @JvmOverloads constructor(
|
||||
button.isSelected = menuState.reversedActions.contains(action)
|
||||
}
|
||||
|
||||
private fun updateTextFieldBorder() {
|
||||
val isExpanded = editText.editableText.lines().count() > 1
|
||||
val borderResource = if (isExpanded || isFullScreen) {
|
||||
R.drawable.bg_composer_rich_edit_text_expanded
|
||||
fun estimateCollapsedHeight(): Int {
|
||||
val editText = this.editText
|
||||
val originalLines = editText.maxLines
|
||||
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 {
|
||||
R.drawable.bg_composer_rich_edit_text_single_line
|
||||
}
|
||||
views.composerEditTextOuterBorder.setBackgroundResource(borderResource)
|
||||
resources.getDimensionPixelSize(R.dimen.rich_text_composer_corner_radius_single_line)
|
||||
}.toFloat()
|
||||
borderShapeDrawable.setCornerSize(cornerSize)
|
||||
}
|
||||
|
||||
override fun replaceFormattedContent(text: CharSequence) {
|
||||
private fun replaceFormattedContent(text: CharSequence) {
|
||||
views.richTextComposerEditText.setHtml(text.toString())
|
||||
}
|
||||
|
||||
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()
|
||||
updateTextFieldBorder(isFullScreen)
|
||||
}
|
||||
|
||||
override fun setTextIfDifferent(text: CharSequence?): Boolean {
|
||||
return editText.setTextIfDifferent(text)
|
||||
}
|
||||
|
||||
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)
|
||||
val result = editText.setTextIfDifferent(text)
|
||||
updateTextFieldBorder(isFullScreen)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun updateEditTextFullScreenState(editText: EditText, isFullScreen: Boolean) {
|
||||
if (isFullScreen) {
|
||||
editText.maxLines = Int.MAX_VALUE
|
||||
// This is a workaround to fix incorrect scroll position when maximised
|
||||
post { editText.requestLayout() }
|
||||
} else {
|
||||
editText.maxLines = maxEditTextLinesWhenCollapsed
|
||||
editText.maxLines = MessageComposerView.MAX_LINES_WHEN_COLLAPSED
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyNewConstraintSet(animate: Boolean, transitionComplete: (() -> Unit)?) {
|
||||
// val wasSendButtonInvisible = views.sendButton.isInvisible
|
||||
if (animate) {
|
||||
animateLayoutChange(animationDuration, transitionComplete)
|
||||
}
|
||||
ConstraintSet().also {
|
||||
it.clone(context, currentConstraintSetId)
|
||||
it.applyTo(this)
|
||||
override fun renderComposerMode(mode: MessageComposerMode) {
|
||||
if (mode is MessageComposerMode.Special) {
|
||||
views.composerModeGroup.isVisible = true
|
||||
replaceFormattedContent(mode.defaultContent)
|
||||
hasRelatedMessage = true
|
||||
editText.showKeyboard(andRequestFocus = true)
|
||||
} else {
|
||||
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(R.string.action_send)
|
||||
hasRelatedMessage = false
|
||||
}
|
||||
|
||||
// Might be updated by view state just after, but avoid blinks
|
||||
// views.sendButton.isInvisible = wasSendButtonInvisible
|
||||
}
|
||||
views.sendButton.apply {
|
||||
if (mode is MessageComposerMode.Edit) {
|
||||
contentDescription = resources.getString(R.string.action_save)
|
||||
setImageResource(R.drawable.ic_composer_rich_text_save)
|
||||
} else {
|
||||
contentDescription = resources.getString(R.string.action_send)
|
||||
setImageResource(R.drawable.ic_rich_composer_send)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setInvisible(isInvisible: Boolean) {
|
||||
this.isInvisible = isInvisible
|
||||
updateTextFieldBorder(isFullScreen)
|
||||
|
||||
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 -> {
|
||||
val senderInfo = mode.event.senderInfo
|
||||
val userName = 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(
|
||||
|
@ -147,7 +147,8 @@ class VoiceMessageViews(
|
||||
}
|
||||
|
||||
fun showRecordingViews() {
|
||||
views.voiceMessageMicButton.setImageResource(R.drawable.ic_voice_mic_recording)
|
||||
views.voiceMessageBackgroundView.isVisible = true
|
||||
views.voiceMessageMicButton.setImageResource(R.drawable.ic_composer_rich_mic_pressed)
|
||||
views.voiceMessageMicButton.setAttributeTintedBackground(R.drawable.circle_with_halo, R.attr.colorPrimary)
|
||||
views.voiceMessageMicButton.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
setMargins(0, 0, 0, 0)
|
||||
@ -172,6 +173,7 @@ class VoiceMessageViews(
|
||||
|
||||
fun hideRecordingViews(recordingState: RecordingUiState) {
|
||||
// We need to animate the lock image first
|
||||
views.voiceMessageBackgroundView.isVisible = false
|
||||
if (recordingState !is RecordingUiState.Locked) {
|
||||
views.voiceMessageLockImage.isVisible = false
|
||||
views.voiceMessageLockImage.animate().translationY(0f).start()
|
||||
@ -278,6 +280,7 @@ class VoiceMessageViews(
|
||||
|
||||
fun showDraftViews() {
|
||||
hideRecordingViews(RecordingUiState.Idle)
|
||||
views.voiceMessageBackgroundView.isVisible = true
|
||||
views.voiceMessageMicButton.isVisible = false
|
||||
views.voiceMessageSendButton.isVisible = true
|
||||
views.voiceMessagePlaybackLayout.isVisible = true
|
||||
@ -288,6 +291,7 @@ class VoiceMessageViews(
|
||||
|
||||
fun showRecordingLockedViews(recordingState: RecordingUiState) {
|
||||
hideRecordingViews(recordingState)
|
||||
views.voiceMessageBackgroundView.isVisible = true
|
||||
views.voiceMessagePlaybackLayout.isVisible = true
|
||||
views.voiceMessagePlaybackTimerIndicator.isVisible = true
|
||||
views.voicePlaybackControlButton.isVisible = false
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
6
vector/src/main/res/drawable/bottomsheet_handle.xml
Normal file
6
vector/src/main/res/drawable/bottomsheet_handle.xml
Normal 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>
|
9
vector/src/main/res/drawable/ic_composer_collapse.xml
Normal file
9
vector/src/main/res/drawable/ic_composer_collapse.xml
Normal 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>
|
@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M17.125,31.5C16.944,31.5 16.795,31.441 16.677,31.323C16.559,31.205 16.5,31.056 16.5,30.875V25.875C16.5,25.694 16.559,25.545 16.677,25.427C16.795,25.309 16.944,25.25 17.125,25.25C17.306,25.25 17.455,25.309 17.573,25.427C17.691,25.545 17.75,25.694 17.75,25.875V29.375L29.375,17.75H25.875C25.694,17.75 25.545,17.691 25.427,17.573C25.309,17.455 25.25,17.306 25.25,17.125C25.25,16.944 25.309,16.795 25.427,16.677C25.545,16.559 25.694,16.5 25.875,16.5H30.875C31.056,16.5 31.205,16.559 31.323,16.677C31.441,16.795 31.5,16.944 31.5,17.125V22.125C31.5,22.306 31.441,22.455 31.323,22.573C31.205,22.691 31.056,22.75 30.875,22.75C30.694,22.75 30.545,22.691 30.427,22.573C30.309,22.455 30.25,22.306 30.25,22.125V18.625L18.625,30.25H22.125C22.306,30.25 22.455,30.309 22.573,30.427C22.691,30.545 22.75,30.694 22.75,30.875C22.75,31.056 22.691,31.205 22.573,31.323C22.455,31.441 22.306,31.5 22.125,31.5H17.125Z"
|
||||
android:fillColor="#C1C6CD"/>
|
||||
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>
|
||||
|
@ -0,0 +1,17 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="52dp"
|
||||
android:height="52dp"
|
||||
android:viewportWidth="52"
|
||||
android:viewportHeight="52">
|
||||
<path
|
||||
android:pathData="M26.173,26.169m-22.763,0a22.763,22.763 0,1 1,45.526 0a22.763,22.763 0,1 1,-45.526 0"
|
||||
android:fillColor="#0DBD8B"/>
|
||||
<path
|
||||
android:pathData="M26,26m-26,0a26,26 0,1 1,52 0a26,26 0,1 1,-52 0"
|
||||
android:strokeAlpha="0.2"
|
||||
android:fillColor="#0DBD8B"
|
||||
android:fillAlpha="0.2"/>
|
||||
<path
|
||||
android:pathData="M26,29.5C27.937,29.5 29.488,27.937 29.488,26L29.5,19C29.5,17.063 27.937,15.5 26,15.5C24.063,15.5 22.5,17.063 22.5,19V26C22.5,27.937 24.063,29.5 26,29.5ZM33.093,26C32.603,26 32.195,26.35 32.125,26.828C31.693,29.873 28.952,31.95 26,31.95C23.048,31.95 20.307,29.885 19.875,26.828C19.805,26.35 19.385,26 18.907,26C18.3,26 17.833,26.537 17.915,27.132C18.452,30.597 21.368,33.315 24.833,33.84V36.5C24.833,37.142 25.358,37.667 26,37.667C26.642,37.667 27.167,37.142 27.167,36.5V33.84C30.62,33.338 33.548,30.597 34.085,27.132C34.167,26.537 33.7,26 33.093,26Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
@ -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>
|
@ -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>
|
16
vector/src/main/res/drawable/ic_composer_rich_text_save.xml
Normal file
16
vector/src/main/res/drawable/ic_composer_rich_text_save.xml
Normal 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>
|
15
vector/src/main/res/drawable/ic_rich_composer_add.xml
Normal file
15
vector/src/main/res/drawable/ic_rich_composer_add.xml
Normal 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>
|
12
vector/src/main/res/drawable/ic_rich_composer_send.xml
Normal file
12
vector/src/main/res/drawable/ic_rich_composer_send.xml
Normal 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>
|
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="52dp"
|
||||
android:height="52dp"
|
||||
android:viewportWidth="52"
|
||||
android:viewportHeight="52">
|
||||
<path
|
||||
android:pathData="M21.2414,18.7749C21.2414,16.051 23.4496,13.8429 26.1734,13.8429C28.8973,13.8429 31.1054,16.051 31.1054,18.7749V26.1509C31.1054,28.8747 28.8973,31.0829 26.1734,31.0829C23.4496,31.0829 21.2414,28.8747 21.2414,26.1509V18.7749ZM17.542,24.2475C18.5968,24.2475 19.4518,25.1025 19.4518,26.1572C19.4518,29.8561 22.4509,32.8596 26.1586,32.8675C26.1637,32.8674 26.1689,32.8674 26.174,32.8674C26.179,32.8674 26.184,32.8674 26.189,32.8675C29.896,32.8589 32.8944,29.8556 32.8944,26.1572C32.8944,25.1025 33.7494,24.2475 34.8041,24.2475C35.8588,24.2475 36.7138,25.1025 36.7138,26.1572C36.7138,31.3227 32.9916,35.6165 28.0837,36.5143V37.24C28.0837,38.2947 27.2287,39.1497 26.174,39.1497C25.1193,39.1497 24.2643,38.2947 24.2643,37.24V36.5147C19.3555,35.6176 15.6323,31.3233 15.6323,26.1572C15.6323,25.1025 16.4873,24.2475 17.542,24.2475Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
@ -1,148 +1,210 @@
|
||||
<?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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:constraintSet="@layout/composer_layout_constraint_set_compact"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- ========================
|
||||
/!\ 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"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/related_message_group"
|
||||
android:layout_width="match_parent"
|
||||
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" />
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<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" />
|
||||
<View
|
||||
android:id="@+id/related_message_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?colorSurface"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/composer_preview_barrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composerRelatedMessageImage"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:importantForAccessibility="no"
|
||||
tools:ignore="MissingPrefix" />
|
||||
<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" />
|
||||
|
||||
<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" />
|
||||
<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" />
|
||||
|
||||
<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" />
|
||||
<TextView
|
||||
android:id="@+id/composerRelatedMessageTitle"
|
||||
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" />
|
||||
|
||||
<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:src="@drawable/ic_attachment"
|
||||
tools:ignore="MissingConstraints" />
|
||||
<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" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/composerEditTextOuterBorder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_composer_edit_text" />
|
||||
<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" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/Widget.Vector.EditText.Composer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusLeft="@id/composerEditText"
|
||||
android:nextFocusUp="@id/composerEditText"
|
||||
tools:hint="@string/room_message_placeholder"
|
||||
tools:ignore="MissingConstraints" />
|
||||
<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" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composerEmojiButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/a11y_open_emoji_picker"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
android:visibility="invisible"
|
||||
app:tint="?vctr_content_tertiary"
|
||||
tools:ignore="MissingConstraints,MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
<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" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:contentDescription="@string/action_send"
|
||||
android:src="@drawable/ic_send"
|
||||
tools:ignore="MissingConstraints" />
|
||||
<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/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" />
|
||||
-->
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</merge>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<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_constraintEnd_toStartOf="@id/composerEditTextOuterBorder"
|
||||
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:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@drawable/bg_composer_edit_text"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/sendButton"
|
||||
app:layout_constraintStart_toEndOf="@id/attachmentButton"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginEnd="12dp" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/Widget.Vector.EditText.Composer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/room_message_placeholder"
|
||||
android:nextFocusLeft="@id/composerEditText"
|
||||
android:nextFocusUp="@id/composerEditText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/composerEmojiButton"
|
||||
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composerEmojiButton"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/a11y_open_emoji_picker"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/attachmentButton"
|
||||
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/attachmentButton"
|
||||
app:layout_goneMarginEnd="8dp"
|
||||
app:tint="?vctr_content_quaternary"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<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"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,197 +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="wrap_content"
|
||||
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_constraintEnd_toStartOf="@id/composerEditTextOuterBorder"
|
||||
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:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/sendButton"
|
||||
app:layout_constraintStart_toEndOf="@id/attachmentButton"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginEnd="12dp" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/Widget.Vector.EditText.Composer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/room_message_placeholder"
|
||||
android:nextFocusLeft="@id/composerEditText"
|
||||
android:nextFocusUp="@id/composerEditText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/composerEmojiButton"
|
||||
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composerEmojiButton"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/a11y_open_emoji_picker"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/attachmentButton"
|
||||
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/attachmentButton"
|
||||
app:layout_goneMarginEnd="8dp"
|
||||
app:tint="?vctr_content_quaternary"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<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"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!--
|
||||
<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>
|
@ -1,197 +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="wrap_content"
|
||||
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_constraintEnd_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/composerEditTextOuterBorder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/sendButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
|
||||
app:layout_goneMarginEnd="12dp" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/Widget.Vector.EditText.Composer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusLeft="@id/composerEditText"
|
||||
android:nextFocusUp="@id/composerEditText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/composerEmojiButton"
|
||||
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
|
||||
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composerEmojiButton"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/a11y_open_emoji_picker"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
app:layout_goneMarginBottom="52dp"
|
||||
app:layout_goneMarginEnd="8dp"
|
||||
app:tint="?vctr_content_quaternary"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<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_constraintTop_toBottomOf="@id/composer_preview_barrier"
|
||||
app:layout_constraintVertical_bias="1"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,183 +1,201 @@
|
||||
<?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:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/composerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:constraintSet="@layout/composer_rich_text_layout_constraint_set_compact"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<!-- ========================
|
||||
/!\ 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:paddingTop="2dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/option_send_files"
|
||||
android:src="@drawable/ic_attachment"
|
||||
tools:ignore="MissingConstraints" />
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/bg_composer_rich_bottom_sheet">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/composerEditTextOuterBorder"
|
||||
android:layout_width="0dp"
|
||||
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:id="@+id/bottomSheetHandle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:nextFocusLeft="@id/richTextComposerEditText"
|
||||
android:nextFocusUp="@id/richTextComposerEditText"
|
||||
tools:hint="@string/room_message_placeholder"
|
||||
tools:text="@tools:sample/lorem/random"
|
||||
tools:ignore="MissingConstraints" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<!-- Use a separate EditText for plain text editing while the rich text editor doesn't support this mode -->
|
||||
<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:gravity="top"
|
||||
android:nextFocusLeft="@id/plainTextComposerEditText"
|
||||
android:nextFocusUp="@id/plainTextComposerEditText"
|
||||
tools:hint="@string/room_message_placeholder"
|
||||
tools:text="@tools:sample/lorem/random"
|
||||
tools:ignore="MissingConstraints" />
|
||||
<View
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="5dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bottomsheet_handle" />
|
||||
|
||||
<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"
|
||||
android:src="@drawable/ic_composer_full_screen"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/rich_text_editor_full_screen_toggle" />
|
||||
</FrameLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:contentDescription="@string/action_send"
|
||||
android:src="@drawable/ic_send"
|
||||
tools:ignore="MissingConstraints" />
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<HorizontalScrollView android:id="@+id/richTextMenuScrollView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none"
|
||||
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">
|
||||
<ImageButton
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="@dimen/composer_attachment_margin"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/option_send_files"
|
||||
android:src="@drawable/ic_rich_composer_add"
|
||||
android:paddingStart="4dp"
|
||||
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
|
||||
android:id="@+id/richTextMenu"
|
||||
<FrameLayout
|
||||
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_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" />
|
||||
|
||||
<!--
|
||||
<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" />
|
||||
-->
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/composerModeGroup"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:constraint_referenced_ids="composerModeIconView,composerModeTitleView,composerModeCloseView" />
|
||||
|
||||
</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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -4,12 +4,13 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent">
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.PlainTextComposerLayout
|
||||
android:id="@+id/composerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:colorBackground"
|
||||
android:minHeight="56dp"
|
||||
android:transitionName="composer"
|
||||
@ -20,7 +21,7 @@
|
||||
android:id="@+id/richTextComposerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:colorBackground"
|
||||
android:background="@drawable/bg_composer_rich_bottom_sheet"
|
||||
android:minHeight="56dp"
|
||||
android:transitionName="composer"
|
||||
android:visibility="gone"
|
||||
|
@ -1,26 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/rootConstraintLayout"
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- ========================
|
||||
/!\ Constraints for this layout are defined in external layout files that are used as constraint set for animation.
|
||||
/!\ These 2 files must be modified to stay coherent!
|
||||
======================== -->
|
||||
|
||||
<View android:id="@+id/scrim"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:visibility="gone"
|
||||
android:background="#44000000" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
@ -52,188 +37,187 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<im.vector.app.features.sync.widget.SyncStateView
|
||||
android:id="@+id/syncStateView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||
|
||||
<im.vector.app.features.location.live.LiveLocationStatusView
|
||||
android:id="@+id/liveLocationStatusIndicator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<im.vector.app.features.call.conference.RemoveJitsiWidgetView
|
||||
android:id="@+id/removeJitsiWidgetView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
android:minHeight="54dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/liveLocationStatusIndicator" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/timelineRecyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:overScrollMode="always"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomBarrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView"
|
||||
tools:listitem="@layout/item_timeline_event_base" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/jumpToReadMarkerView"
|
||||
style="?vctr_jump_to_unread_style"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/room_jump_to_first_unread"
|
||||
android:visibility="invisible"
|
||||
app:chipIcon="@drawable/ic_jump_to_unread"
|
||||
app:chipIconTint="?colorPrimary"
|
||||
app:closeIcon="@drawable/ic_close_24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView" />
|
||||
|
||||
<im.vector.app.core.ui.views.NotificationAreaView
|
||||
android:id="@+id/notificationAreaView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/failedMessagesWarningStub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inflatedId="@+id/failedMessagesWarningStub"
|
||||
android:layout="@layout/view_stub_failed_message_warning_layout"
|
||||
app:layout_constraintBottom_toTopOf="@id/composerContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:layout_height="300dp" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/composerContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/voiceMessageRecorderContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/inviteViewStub"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:layout="@layout/view_stub_invite_layout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/bottomBarrier"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:barrierDirection="top"
|
||||
app:constraint_referenced_ids="composerContainer,notificationAreaView,failedMessagesWarningStub" />
|
||||
|
||||
<im.vector.app.core.platform.BadgeFloatingActionButton
|
||||
android:id="@+id/jumpToBottomView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/a11y_jump_to_bottom"
|
||||
android:src="@drawable/ic_expand_more"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="#FFFFFF"
|
||||
app:badgeBackgroundColor="?colorPrimary"
|
||||
app:badgeTextColor="?colorOnPrimary"
|
||||
app:badgeTextPadding="2dp"
|
||||
app:badgeTextSize="10sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomBarrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:tint="@android:color/black" />
|
||||
|
||||
<im.vector.app.core.ui.views.CompatKonfetti
|
||||
android:id="@+id/viewKonfetti"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<com.jetradarmobile.snowfall.SnowfallView
|
||||
android:id="@+id/viewSnowFall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?vctr_chat_effect_snow_background"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<!-- Room not found layout -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/roomNotFound"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:elevation="10dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="gone">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/rootConstraintLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomNotFoundIcon"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_alert_triangle"
|
||||
app:layout_constraintBottom_toTopOf="@id/roomNotFoundText"
|
||||
<im.vector.app.features.sync.widget.SyncStateView
|
||||
android:id="@+id/syncStateView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNotFoundText"
|
||||
style="@style/Widget.Vector.TextView.Subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
<im.vector.app.features.location.live.LiveLocationStatusView
|
||||
android:id="@+id/liveLocationStatusIndicator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/timeline_error_room_not_found"
|
||||
android:textColor="?vctr_content_primary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<im.vector.app.features.call.conference.RemoveJitsiWidgetView
|
||||
android:id="@+id/removeJitsiWidgetView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
android:minHeight="54dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/liveLocationStatusIndicator" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/timelineRecyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:overScrollMode="always"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomNotFoundIcon" />
|
||||
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView"
|
||||
tools:listitem="@layout/item_timeline_event_base" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/jumpToReadMarkerView"
|
||||
style="?vctr_jump_to_unread_style"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/room_jump_to_first_unread"
|
||||
android:visibility="invisible"
|
||||
app:chipIcon="@drawable/ic_jump_to_unread"
|
||||
app:chipIconTint="?colorPrimary"
|
||||
app:closeIcon="@drawable/ic_close_24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView" />
|
||||
|
||||
<im.vector.app.core.ui.views.NotificationAreaView
|
||||
android:id="@+id/notificationAreaView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/failedMessagesWarningStub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inflatedId="@+id/failedMessagesWarningStub"
|
||||
android:layout="@layout/view_stub_failed_message_warning_layout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:layout_height="300dp" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/inviteViewStub"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:layout="@layout/view_stub_invite_layout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<im.vector.app.core.platform.BadgeFloatingActionButton
|
||||
android:id="@+id/jumpToBottomView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/a11y_jump_to_bottom"
|
||||
android:src="@drawable/ic_expand_more"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="#FFFFFF"
|
||||
app:badgeBackgroundColor="?colorPrimary"
|
||||
app:badgeTextColor="?colorOnPrimary"
|
||||
app:badgeTextPadding="2dp"
|
||||
app:badgeTextSize="10sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:tint="@android:color/black" />
|
||||
|
||||
<im.vector.app.core.ui.views.CompatKonfetti
|
||||
android:id="@+id/viewKonfetti"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<com.jetradarmobile.snowfall.SnowfallView
|
||||
android:id="@+id/viewSnowFall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?vctr_chat_effect_snow_background"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<!-- Room not found layout -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/roomNotFound"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:elevation="10dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomNotFoundIcon"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_alert_triangle"
|
||||
app:layout_constraintBottom_toTopOf="@id/roomNotFoundText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNotFoundText"
|
||||
style="@style/Widget.Vector.TextView.Subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/timeline_error_room_not_found"
|
||||
android:textColor="?vctr_content_primary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomNotFoundIcon" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/composerContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:translationZ="10dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_behavior="im.vector.app.core.utils.ExpandingBottomSheetBehavior" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/voiceMessageRecorderContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:visibility="visible"
|
||||
android:translationZ="10dp" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
@ -1,258 +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/rootConstraintLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- ========================
|
||||
/!\ Constraints for this layout are defined in external layout files that are used as constraint set for animation.
|
||||
/!\ These 2 files must be modified to stay coherent!
|
||||
======================== -->
|
||||
|
||||
<View android:id="@+id/scrim"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:translationZ="10dp"
|
||||
android:visibility="visible"
|
||||
android:background="#44000000" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<im.vector.app.core.ui.views.CurrentCallsView
|
||||
android:id="@+id/currentCallsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/roomToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:transitionName="toolbar">
|
||||
|
||||
<include
|
||||
android:id="@+id/includeThreadToolbar"
|
||||
layout="@layout/view_room_detail_thread_toolbar" />
|
||||
|
||||
<include
|
||||
android:id="@+id/includeRoomToolbar"
|
||||
layout="@layout/view_room_detail_toolbar" />
|
||||
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<im.vector.app.features.sync.widget.SyncStateView
|
||||
android:id="@+id/syncStateView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||
|
||||
<im.vector.app.features.location.live.LiveLocationStatusView
|
||||
android:id="@+id/liveLocationStatusIndicator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<im.vector.app.features.call.conference.RemoveJitsiWidgetView
|
||||
android:id="@+id/removeJitsiWidgetView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
android:minHeight="54dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/liveLocationStatusIndicator" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/timelineRecyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:overScrollMode="always"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toTopOf="@id/typingMessageView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView"
|
||||
tools:listitem="@layout/item_timeline_event_base" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/jumpToReadMarkerView"
|
||||
style="?vctr_jump_to_unread_style"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/room_jump_to_first_unread"
|
||||
android:visibility="invisible"
|
||||
app:chipIcon="@drawable/ic_jump_to_unread"
|
||||
app:chipIconTint="?colorPrimary"
|
||||
app:closeIcon="@drawable/ic_close_24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/removeJitsiWidgetView" />
|
||||
|
||||
<im.vector.app.core.ui.views.TypingMessageView
|
||||
android:id="@+id/typingMessageView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomBarrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/timelineRecyclerView" />
|
||||
|
||||
<im.vector.app.core.ui.views.NotificationAreaView
|
||||
android:id="@+id/notificationAreaView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/failedMessagesWarningStub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inflatedId="@+id/failedMessagesWarningStub"
|
||||
android:layout="@layout/view_stub_failed_message_warning_layout"
|
||||
app:layout_constraintBottom_toTopOf="@id/composerContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:layout_height="300dp" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/composerContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:translationZ="48dp"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/voiceMessageRecorderContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:translationZ="48dp"
|
||||
android:background="?android:colorBackground"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/inviteViewStub"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:layout="@layout/view_stub_invite_layout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/bottomBarrier"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:barrierDirection="top"
|
||||
app:constraint_referenced_ids="notificationAreaView,failedMessagesWarningStub" />
|
||||
|
||||
<im.vector.app.core.platform.BadgeFloatingActionButton
|
||||
android:id="@+id/jumpToBottomView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/a11y_jump_to_bottom"
|
||||
android:src="@drawable/ic_expand_more"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="#FFFFFF"
|
||||
app:badgeBackgroundColor="?colorPrimary"
|
||||
app:badgeTextColor="?colorOnPrimary"
|
||||
app:badgeTextPadding="2dp"
|
||||
app:badgeTextSize="10sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomBarrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:tint="@android:color/black" />
|
||||
|
||||
<im.vector.app.core.ui.views.CompatKonfetti
|
||||
android:id="@+id/viewKonfetti"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<com.jetradarmobile.snowfall.SnowfallView
|
||||
android:id="@+id/viewSnowFall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?vctr_chat_effect_snow_background"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<!-- Room not found layout -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/roomNotFound"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
android:elevation="10dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomNotFoundIcon"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_alert_triangle"
|
||||
app:layout_constraintBottom_toTopOf="@id/roomNotFoundText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNotFoundText"
|
||||
style="@style/Widget.Vector.TextView.Subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/timeline_error_room_not_found"
|
||||
android:textColor="?vctr_content_primary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomNotFoundIcon" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -2,8 +2,8 @@
|
||||
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_width="@dimen/rich_text_composer_menu_item_size"
|
||||
android:layout_height="@dimen/rich_text_composer_menu_item_size"
|
||||
android:layout_marginHorizontal="2dp"
|
||||
android:background="@drawable/bg_rich_text_menu_button"
|
||||
app:tint="@color/selector_rich_text_menu_icon"
|
||||
|
@ -7,13 +7,23 @@
|
||||
android:layout_height="match_parent"
|
||||
android:minHeight="200dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/voiceMessageBackgroundView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/composer_min_height"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:background="?android:colorBackground" />
|
||||
|
||||
<View
|
||||
android:id="@+id/voiceMessageLockBackground"
|
||||
android:layout_width="78dp"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="180dp"
|
||||
android:background="@drawable/bg_voice_message_lock"
|
||||
android:backgroundTint="?vctr_system"
|
||||
android:visibility="gone"
|
||||
android:layout_marginEnd="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/voiceMessageMicButton"
|
||||
tools:translationY="-180dp"
|
||||
@ -26,7 +36,7 @@
|
||||
android:minWidth="32dp"
|
||||
android:minHeight="32dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/a11y_start_voice_message"
|
||||
android:src="@drawable/ic_microphone"
|
||||
@ -100,7 +110,6 @@
|
||||
android:id="@+id/voiceMessageSlideToCancelDivider"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:colorBackground"
|
||||
app:layout_constraintBottom_toBottomOf="@id/voiceMessageTimer"
|
||||
app:layout_constraintStart_toEndOf="@id/voiceMessageTimer"
|
||||
app:layout_constraintTop_toTopOf="@id/voiceMessageTimer" />
|
||||
@ -109,7 +118,7 @@
|
||||
android:id="@+id/voiceMessageLockImage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="28dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_voice_message_unlocked"
|
||||
android:visibility="gone"
|
||||
@ -123,7 +132,6 @@
|
||||
android:id="@+id/voiceMessageLockArrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_voice_lock_arrow"
|
||||
|
Loading…
x
Reference in New Issue
Block a user