Merge pull request #134 from vector-im/feature/refactor_timeline_layouts

Refactoring / Use view ViewStub to avoid layout xml duplication
This commit is contained in:
Valere 2019-05-13 16:59:13 +02:00 committed by GitHub
commit 8929898397
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 492 additions and 388 deletions

View File

@ -20,6 +20,7 @@ import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.widget.ImageView import android.widget.ImageView
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import androidx.annotation.ColorRes
import androidx.annotation.UiThread import androidx.annotation.UiThread
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
@ -77,31 +78,35 @@ object AvatarRenderer {


@AnyThread @AnyThread
fun getPlaceholderDrawable(context: Context, identifier: String, text: String): Drawable { fun getPlaceholderDrawable(context: Context, identifier: String, text: String): Drawable {
val avatarColor = ContextCompat.getColor(context, getAvatarColor(identifier)) val avatarColor = ContextCompat.getColor(context, getColorFromUserId(identifier))
return if (text.isEmpty()) { return if (text.isEmpty()) {
TextDrawable.builder().buildRound("", avatarColor) TextDrawable.builder().buildRound("", avatarColor)
} else { } else {
val isUserId = MatrixPatterns.isUserId(text) val isUserId = MatrixPatterns.isUserId(text)
val firstLetterIndex = if (isUserId) 1 else 0 val firstLetterIndex = if (isUserId) 1 else 0
val firstLetter = text[firstLetterIndex].toString().toUpperCase() val firstLetter = text[firstLetterIndex].toString().toUpperCase()
TextDrawable.builder().buildRound(firstLetter, avatarColor) TextDrawable.builder()
.beginConfig()
.bold()
.endConfig()
.buildRound(firstLetter, avatarColor)
} }
} }


// PRIVATE API ********************************************************************************* // PRIVATE API *********************************************************************************




private fun getAvatarColor(text: String? = null): Int { // private fun getAvatarColor(text: String? = null): Int {
var colorIndex: Long = 0 // var colorIndex: Long = 0
if (!text.isNullOrEmpty()) { // if (!text.isNullOrEmpty()) {
var sum: Long = 0 // var sum: Long = 0
for (i in 0 until text.length) { // for (i in 0 until text.length) {
sum += text[i].toLong() // sum += text[i].toLong()
} // }
colorIndex = sum % AVATAR_COLOR_LIST.size // colorIndex = sum % AVATAR_COLOR_LIST.size
} // }
return AVATAR_COLOR_LIST[colorIndex.toInt()] // return AVATAR_COLOR_LIST[colorIndex.toInt()]
} // }


private fun buildGlideRequest(glideRequest: GlideRequests, avatarUrl: String?): GlideRequest<Drawable> { private fun buildGlideRequest(glideRequest: GlideRequests, avatarUrl: String?): GlideRequest<Drawable> {
val resolvedUrl = Matrix.getInstance().currentSession!!.contentUrlResolver() val resolvedUrl = Matrix.getInstance().currentSession!!.contentUrlResolver()
@ -112,4 +117,32 @@ object AvatarRenderer {
.apply(RequestOptions.circleCropTransform()) .apply(RequestOptions.circleCropTransform())
} }



//Based on riot-web implementation
@ColorRes
fun getColorFromUserId(sender: String): Int {
var hash = 0
var i = 0
var chr: Char
if (sender.isEmpty()) {
return R.color.username_1
}
while (i < sender.length) {
chr = sender[i]
hash = (hash shl 5) - hash + chr.toInt()
hash = hash or 0
i++
}
val cI = Math.abs(hash) % 8 + 1
return when (cI) {
1 -> R.color.username_1
2 -> R.color.username_2
3 -> R.color.username_3
4 -> R.color.username_4
5 -> R.color.username_5
6 -> R.color.username_6
7 -> R.color.username_7
else -> R.color.username_8
}
}
} }

View File

@ -32,6 +32,7 @@ import im.vector.riotredesign.core.extensions.localDateTime
import im.vector.riotredesign.core.linkify.VectorLinkify import im.vector.riotredesign.core.linkify.VectorLinkify
import im.vector.riotredesign.core.resources.ColorProvider import im.vector.riotredesign.core.resources.ColorProvider
import im.vector.riotredesign.core.utils.DebouncedClickListener import im.vector.riotredesign.core.utils.DebouncedClickListener
import im.vector.riotredesign.features.home.AvatarRenderer
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
@ -70,7 +71,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
val avatarUrl = event.senderAvatar val avatarUrl = event.senderAvatar
val memberName = event.senderName ?: event.root.sender ?: "" val memberName = event.senderName ?: event.root.sender ?: ""
val formattedMemberName = span(memberName) { val formattedMemberName = span(memberName) {
textColor = colorProvider.getColor(getColorFor(event.root.sender ?: "")) textColor = colorProvider.getColor(AvatarRenderer.getColorFromUserId(event.root.sender ?: ""))
} }
val informationData = MessageInformationData(eventId = eventId, val informationData = MessageInformationData(eventId = eventId,
senderId = event.root.sender ?: "", senderId = event.root.sender ?: "",

View File

@ -19,13 +19,12 @@ package im.vector.riotredesign.features.home.room.detail.timeline.item
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import im.vector.riotredesign.R
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.jakewharton.rxbinding2.view.RxView
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.AvatarRenderer


abstract class AbsMessageItem<H : AbsMessageItem.Holder> : VectorEpoxyModel<H>() {
abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {


abstract val informationData: MessageInformationData abstract val informationData: MessageInformationData


@ -41,6 +40,13 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : VectorEpoxyModel<H>()
override fun bind(holder: H) { override fun bind(holder: H) {
super.bind(holder) super.bind(holder)
if (informationData.showInformation) { if (informationData.showInformation) {

holder.avatarImageView.layoutParams = holder.avatarImageView.layoutParams?.apply {
val size = dpToPx(avatarStyle.avatarSizeDP, holder.view.context)
height = size
width = size
}

holder.avatarImageView.visibility = View.VISIBLE holder.avatarImageView.visibility = View.VISIBLE
holder.avatarImageView.setOnClickListener(avatarClickListener) holder.avatarImageView.setOnClickListener(avatarClickListener)
holder.memberNameView.visibility = View.VISIBLE holder.memberNameView.visibility = View.VISIBLE
@ -63,10 +69,11 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : VectorEpoxyModel<H>()
alpha = if (informationData.sendState.isSent()) 1f else 0.5f alpha = if (informationData.sendState.isSent()) 1f else 0.5f
} }


abstract class Holder : VectorEpoxyHolder() { abstract class Holder : BaseHolder() {
abstract val avatarImageView: ImageView
abstract val memberNameView: TextView val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
abstract val timeView: TextView val memberNameView by bind<TextView>(R.id.messageMemberNameView)
val timeView by bind<TextView>(R.id.messageTimeView)
} }


} }

View File

@ -0,0 +1,82 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotredesign.features.home.room.detail.timeline.item

import android.content.Context
import android.util.TypedValue
import android.view.View
import android.view.ViewStub
import androidx.annotation.IdRes
import androidx.constraintlayout.widget.Guideline
import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel

abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>() {

var avatarStyle: AvatarStyle = Companion.AvatarStyle.SMALL

override fun bind(holder: H) {
super.bind(holder)
//optimize?
val px = dpToPx(avatarStyle.avatarSizeDP, holder.view.context)
holder.leftGuideline.setGuidelineBegin(px)
}


override fun getViewType(): Int {
return getStubType()
}

abstract fun getStubType(): Int


abstract class BaseHolder : VectorEpoxyHolder() {

val leftGuideline by bind<Guideline>(R.id.messageStartGuideline)

@IdRes
abstract fun getStubId(): Int

override fun bindView(itemView: View) {
super.bindView(itemView)
inflateStub()
}

private fun inflateStub() {
view.findViewById<ViewStub>(getStubId()).inflate()
}

}

companion object {

enum class AvatarStyle(val avatarSizeDP: Int) {
BIG(50),
MEDIUM(40),
SMALL(30),
NONE(0)
}

fun dpToPx(dp: Int, context: Context): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp.toFloat(),
context.resources.displayMetrics
).toInt()
}
}
}

View File

@ -20,19 +20,26 @@ import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel


@EpoxyModelClass(layout = R.layout.item_timeline_event_default) @EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
abstract class DefaultItem : VectorEpoxyModel<DefaultItem.Holder>() { abstract class DefaultItem : BaseEventItem<DefaultItem.Holder>() {


@EpoxyAttribute var text: CharSequence? = null @EpoxyAttribute
var text: CharSequence? = null


override fun bind(holder: Holder) { override fun bind(holder: Holder) {
holder.messageView.text = text holder.messageView.text = text
} }


class Holder : VectorEpoxyHolder() { override fun getStubType(): Int = STUB_ID

class Holder : BaseHolder() {
override fun getStubId(): Int = STUB_ID

val messageView by bind<TextView>(R.id.stateMessageView) val messageView by bind<TextView>(R.id.stateMessageView)
} }

companion object {
private val STUB_ID = R.id.messageContentDefaultStub
}
} }

View File

@ -24,15 +24,14 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.view.children import androidx.core.view.children
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.AvatarRenderer



data class MergedHeaderItem(private val isCollapsed: Boolean, data class MergedHeaderItem(private val isCollapsed: Boolean,
private val mergeId: String, private val mergeId: String,
private val mergeData: List<Data>, private val mergeData: List<Data>,
private val onCollapsedStateChanged: (Boolean) -> Unit private val onCollapsedStateChanged: (Boolean) -> Unit
) : VectorEpoxyModel<MergedHeaderItem.Holder>() { ) : BaseEventItem<MergedHeaderItem.Holder>() {


private val distinctMergeData = mergeData.distinctBy { it.userId } private val distinctMergeData = mergeData.distinctBy { it.userId }


@ -41,13 +40,15 @@ data class MergedHeaderItem(private val isCollapsed: Boolean,
} }


override fun getDefaultLayout(): Int { override fun getDefaultLayout(): Int {
return R.layout.item_timeline_event_merged_header return R.layout.item_timeline_event_base_noinfo
} }


override fun createNewHolder(): Holder { override fun createNewHolder(): Holder {
return Holder() return Holder()
} }


override fun getStubType(): Int = STUB_ID

override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
holder.expandView.setOnClickListener { holder.expandView.setOnClickListener {
@ -84,11 +85,17 @@ data class MergedHeaderItem(private val isCollapsed: Boolean,
val avatarUrl: String? val avatarUrl: String?
) )


class Holder : VectorEpoxyHolder() { class Holder : BaseHolder() {
override fun getStubId(): Int = STUB_ID

val expandView by bind<TextView>(R.id.itemMergedExpandTextView) val expandView by bind<TextView>(R.id.itemMergedExpandTextView)
val summaryView by bind<TextView>(R.id.itemMergedSummaryTextView) val summaryView by bind<TextView>(R.id.itemMergedSummaryTextView)
val separatorView by bind<View>(R.id.itemMergedSeparatorView) val separatorView by bind<View>(R.id.itemMergedSeparatorView)
val avatarListView by bind<ViewGroup>(R.id.itemMergedAvatarListView) val avatarListView by bind<ViewGroup>(R.id.itemMergedAvatarListView)


} }

companion object {
private val STUB_ID = R.id.messageContentMergedheaderStub
}
} }

View File

@ -26,13 +26,18 @@ import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotredesign.R import im.vector.riotredesign.R


@EpoxyModelClass(layout = R.layout.item_timeline_event_file_message) @EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() { abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {


@EpoxyAttribute var filename: CharSequence = "" @EpoxyAttribute
@EpoxyAttribute @DrawableRes var iconRes: Int = 0 var filename: CharSequence = ""
@EpoxyAttribute override lateinit var informationData: MessageInformationData @EpoxyAttribute
@EpoxyAttribute var clickListener: View.OnClickListener? = null @DrawableRes
var iconRes: Int = 0
@EpoxyAttribute
override lateinit var informationData: MessageInformationData
@EpoxyAttribute
var clickListener: View.OnClickListener? = null


override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
@ -43,15 +48,19 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
holder.filenameView.paintFlags = (holder.filenameView.paintFlags or Paint.UNDERLINE_TEXT_FLAG) holder.filenameView.paintFlags = (holder.filenameView.paintFlags or Paint.UNDERLINE_TEXT_FLAG)
} }


override fun getStubType(): Int = STUB_ID


class Holder : AbsMessageItem.Holder() { class Holder : AbsMessageItem.Holder() {
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView) override fun getStubId(): Int = STUB_ID
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
override val timeView by bind<TextView>(R.id.messageTimeView)
val fileLayout by bind<ViewGroup>(R.id.messageFileLayout) val fileLayout by bind<ViewGroup>(R.id.messageFileLayout)
val fileImageView by bind<ImageView>(R.id.messageFileImageView) val fileImageView by bind<ImageView>(R.id.messageFileImageView)
val filenameView by bind<TextView>(R.id.messageFilenameView) val filenameView by bind<TextView>(R.id.messageFilenameView)

} }


companion object {
private val STUB_ID = R.id.messageContentFileStub
}


} }

View File

@ -19,20 +19,23 @@ package im.vector.riotredesign.features.home.room.detail.timeline.item
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.riotredesign.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.ImageContentRenderer


@EpoxyModelClass(layout = R.layout.item_timeline_event_image_video_message) @EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Holder>() { abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Holder>() {


@EpoxyAttribute lateinit var mediaData: ImageContentRenderer.Data @EpoxyAttribute
@EpoxyAttribute override lateinit var informationData: MessageInformationData lateinit var mediaData: ImageContentRenderer.Data
@EpoxyAttribute var playable: Boolean = false @EpoxyAttribute
@EpoxyAttribute var clickListener: View.OnClickListener? = null override lateinit var informationData: MessageInformationData
@EpoxyAttribute
var playable: Boolean = false
@EpoxyAttribute
var clickListener: View.OnClickListener? = null


override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
@ -49,13 +52,21 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
super.unbind(holder) super.unbind(holder)
} }


override fun getStubType(): Int = STUB_ID

class Holder : AbsMessageItem.Holder() { class Holder : AbsMessageItem.Holder() {
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
override val memberNameView by bind<TextView>(R.id.messageMemberNameView) override fun getStubId(): Int = STUB_ID
override val timeView by bind<TextView>(R.id.messageTimeView)
val progressLayout by bind<ViewGroup>(R.id.messageMediaUploadProgressLayout) val progressLayout by bind<ViewGroup>(R.id.messageMediaUploadProgressLayout)
val imageView by bind<ImageView>(R.id.messageThumbnailView) val imageView by bind<ImageView>(R.id.messageThumbnailView)
val playContentView by bind<ImageView>(R.id.messageMediaPlayView) val playContentView by bind<ImageView>(R.id.messageMediaPlayView)

}


companion object {
private val STUB_ID = R.id.messageContentMediaStub
} }


} }

View File

@ -16,6 +16,7 @@


package im.vector.riotredesign.features.home.room.detail.timeline.item package im.vector.riotredesign.features.home.room.detail.timeline.item


import android.text.Spannable
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
@ -33,7 +34,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext


@EpoxyModelClass(layout = R.layout.item_timeline_event_text_message) @EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() { abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {


@EpoxyAttribute @EpoxyAttribute
@ -67,12 +68,12 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
} }
} }


override fun getStubType(): Int = R.id.messageContentTextStub

class Holder : AbsMessageItem.Holder() { class Holder : AbsMessageItem.Holder() {
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
override val timeView by bind<TextView>(R.id.messageTimeView)
val messageView by bind<AppCompatTextView>(R.id.messageTextView) val messageView by bind<AppCompatTextView>(R.id.messageTextView)
override fun getStubId(): Int = R.id.messageContentTextStub

} }



} }

View File

@ -22,30 +22,41 @@ import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.AvatarRenderer


@EpoxyModelClass(layout = R.layout.item_timeline_event_notice) @EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo)
abstract class NoticeItem : VectorEpoxyModel<NoticeItem.Holder>() { abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {


@EpoxyAttribute var noticeText: CharSequence? = null @EpoxyAttribute
@EpoxyAttribute var avatarUrl: String? = null var noticeText: CharSequence? = null
@EpoxyAttribute var userId: String = "" @EpoxyAttribute
@EpoxyAttribute var memberName: CharSequence? = null var avatarUrl: String? = null
@EpoxyAttribute
var userId: String = ""
@EpoxyAttribute
var memberName: CharSequence? = null




@EpoxyAttribute @EpoxyAttribute
var longClickListener: View.OnLongClickListener? = null var longClickListener: View.OnLongClickListener? = null


override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder)
holder.noticeTextView.text = noticeText holder.noticeTextView.text = noticeText
AvatarRenderer.render(avatarUrl, userId, memberName?.toString(), holder.avatarImageView) AvatarRenderer.render(avatarUrl, userId, memberName?.toString(), holder.avatarImageView)
holder.view.setOnLongClickListener(longClickListener) holder.view.setOnLongClickListener(longClickListener)
} }


class Holder : VectorEpoxyHolder() { override fun getStubType(): Int = STUB_ID

class Holder : BaseHolder() {
override fun getStubId(): Int = STUB_ID

val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView) val avatarImageView by bind<ImageView>(R.id.itemNoticeAvatarView)
val noticeTextView by bind<TextView>(R.id.itemNoticeTextView) val noticeTextView by bind<TextView>(R.id.itemNoticeTextView)
} }

companion object {
private val STUB_ID = R.id.messageContentNoticeStub
}
} }

View File

@ -4,37 +4,44 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:addStatesFromChildren="true" android:addStatesFromChildren="true"
android:paddingLeft="16dp" android:background="?attr/selectableItemBackground"
android:paddingRight="16dp"> android:paddingLeft="8dp"
android:paddingRight="8dp">




<ImageView <ImageView
android:id="@+id/messageAvatarImageView" android:id="@+id/messageAvatarImageView"
android:layout_width="44dp" android:layout_width="44dp"
android:layout_height="44dp" android:layout_height="44dp"
android:layout_marginTop="8dp" android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />


<androidx.constraintlayout.widget.Guideline
android:id="@+id/messageStartGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_constraintGuide_begin="44dp" />

<TextView <TextView
android:id="@+id/messageMemberNameView" android:id="@+id/messageMemberNameView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="56dp" android:layout_marginStart="8dp"
android:layout_marginLeft="56dp" android:layout_marginLeft="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="4dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="4dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/messageTimeView" app:layout_constraintEnd_toStartOf="@+id/messageTimeView"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toEndOf="@id/messageStartGuideline"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" /> tools:text="@tools:sample/full_names" />


@ -51,21 +58,26 @@
app:layout_constraintTop_toTopOf="@id/messageMemberNameView" app:layout_constraintTop_toTopOf="@id/messageMemberNameView"
tools:text="@tools:sample/date/hhmm" /> tools:text="@tools:sample/date/hhmm" />


<TextView
android:id="@+id/messageTextView" <ViewStub
android:layout_width="0dp" android:id="@+id/messageContentTextStub"
android:layout_height="wrap_content" style="@style/TimelineContentStubLayoutParams"
android:layout_marginStart="56dp" android:inflatedId="@id/messageTextView"
android:layout_marginLeft="56dp" android:layout="@layout/item_timeline_event_text_message_stub"
android:layout_marginBottom="8dp" tools:ignore="MissingConstraints"
android:clickable="true" tools:visibility="visible" />
android:textColor="@color/dark_grey"
android:textSize="14sp" <ViewStub
app:layout_constraintBottom_toBottomOf="parent" android:id="@+id/messageContentMediaStub"
app:layout_constraintEnd_toEndOf="parent" style="@style/TimelineContentStubLayoutParams"
app:layout_constraintStart_toStartOf="parent" android:layout="@layout/item_timeline_event_media_message_stub"
app:layout_constraintTop_toBottomOf="@+id/messageMemberNameView" tools:ignore="MissingConstraints" />
tools:text="Alright finished work, heading there in about 20 mins…Ping me when youre outside" />
<ViewStub
android:id="@+id/messageContentFileStub"
style="@style/TimelineContentStubLayoutParams"
android:layout="@layout/item_timeline_event_file_stub"
tools:ignore="MissingConstraints" />




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

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:addStatesFromChildren="true"
android:paddingLeft="8dp"
android:paddingRight="8dp">

<androidx.constraintlayout.widget.Guideline
android:id="@+id/messageStartGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_constraintGuide_begin="44dp" />

<ViewStub
android:id="@+id/messageContentNoticeStub"
style="@style/TimelineContentStubNoInfoLayoutParams"
android:layout="@layout/item_timeline_event_notice_stub"
tools:ignore="MissingConstraints"
tools:visibility="visible" />

<ViewStub
android:id="@+id/messageContentDefaultStub"
style="@style/TimelineContentStubNoInfoLayoutParams"
android:inflatedId="@+id/stateMessageView"
android:layout="@layout/item_timeline_event_default_stub"
tools:ignore="MissingConstraints" />

<ViewStub
android:id="@+id/messageContentBlankStub"
style="@style/TimelineContentStubNoInfoLayoutParams"
android:layout="@layout/item_timeline_event_blank_stub"
tools:ignore="MissingConstraints" />

<ViewStub
android:id="@+id/messageContentMergedheaderStub"
style="@style/TimelineContentStubNoInfoLayoutParams"
android:layout="@layout/item_timeline_event_merged_header_stub"
tools:ignore="MissingConstraints" />


</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -4,10 +4,8 @@
android:id="@+id/stateMessageView" android:id="@+id/stateMessageView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:padding="16dp" android:padding="8dp"
android:textColor="?attr/colorAccent" android:textColor="?attr/colorAccent"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="italic" android:textStyle="italic"

View File

@ -1,134 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2019 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:addStatesFromChildren="true"
android:paddingLeft="16dp"
android:paddingRight="16dp">


<ImageView
android:id="@+id/messageAvatarImageView"
android:layout_width="@dimen/chat_avatar_size"
android:layout_height="@dimen/chat_avatar_size"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />

<TextView
android:id="@+id/messageMemberNameView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="15sp"
app:layout_constraintEnd_toStartOf="@+id/messageTimeView"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" />


<TextView
android:id="@+id/messageTimeView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:textColor="@color/brown_grey"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintTop_toTopOf="@id/messageMemberNameView"
tools:text="@tools:sample/date/hhmm" />


<LinearLayout
android:id="@+id/messageFileLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/messageMemberNameView">

<ImageView
android:id="@+id/messageFilee2eIcon"
android:layout_width="14dp"
android:layout_height="14dp"
android:src="@drawable/e2e_verified"
android:visibility="gone" />

<!-- the media type -->
<ImageView
android:id="@+id/messageFileImageView"
android:layout_width="@dimen/chat_avatar_size"
android:layout_height="@dimen/chat_avatar_size"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:src="@drawable/filetype_image" />

<!-- the media -->
<TextView
android:id="@+id/messageFilenameView"
android:layout_width="0dp"
android:layout_height="@dimen/chat_avatar_size"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_weight="1"
android:autoLink="none"
android:gravity="center_vertical"
tools:text="A filename here" />

</LinearLayout>


<include
android:id="@+id/messageMediaUploadProgressLayout"
layout="@layout/media_upload_download_progress_layout"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/messageFileLayout"
tools:visibility="visible" />


</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:id="@+id/messageFileLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:duplicateParentState="true"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<ImageView
android:id="@+id/messageFilee2eIcon"
android:layout_width="14dp"
android:layout_height="14dp"
android:src="@drawable/e2e_verified"
android:visibility="gone" />

<!-- the media type -->
<ImageView
android:id="@+id/messageFileImageView"
android:layout_width="@dimen/chat_avatar_size"
android:layout_height="@dimen/chat_avatar_size"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:src="@drawable/filetype_image" />

<!-- the media -->
<TextView
android:id="@+id/messageFilenameView"
android:layout_width="0dp"
android:layout_height="@dimen/chat_avatar_size"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_weight="1"
android:autoLink="none"
android:gravity="center_vertical"
tools:text="A filename here" />

</LinearLayout>

<include
android:id="@+id/messageMediaUploadProgressLayout"
layout="@layout/media_upload_download_progress_layout"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/messageFileLayout"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2019 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingLeft="16dp"
android:addStatesFromChildren="true"
android:paddingRight="16dp">


<ImageView
android:id="@+id/messageAvatarImageView"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />

<TextView
android:id="@+id/messageMemberNameView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="56dp"
android:layout_marginLeft="56dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="15sp"
app:layout_constraintEnd_toStartOf="@+id/messageTimeView"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" />


<TextView
android:id="@+id/messageTimeView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:textColor="@color/brown_grey"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintTop_toTopOf="@id/messageMemberNameView"
tools:text="@tools:sample/date/hhmm" />

<ImageView
android:id="@+id/messageThumbnailView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:foreground="?attr/selectableItemBackground"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/messageMemberNameView"
tools:layout_height="300dp"
tools:srcCompat="@tools:sample/backgrounds/scenic" />

<ImageView
android:id="@+id/messageMediaPlayView"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_material_play_circle"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/messageThumbnailView"
app:layout_constraintEnd_toEndOf="@id/messageThumbnailView"
app:layout_constraintStart_toStartOf="@id/messageThumbnailView"
app:layout_constraintTop_toTopOf="@id/messageThumbnailView"
tools:visibility="visible" />


<include
android:id="@+id/messageMediaUploadProgressLayout"
layout="@layout/media_upload_download_progress_layout"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/messageThumbnailView"
tools:visibility="visible" />


</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/messageThumbnailView"
android:layout_width="375dp"
android:layout_height="0dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_height="300dp" />

<ImageView
android:id="@+id/messageMediaPlayView"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_material_play_circle"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/messageThumbnailView"
app:layout_constraintEnd_toEndOf="@id/messageThumbnailView"
app:layout_constraintStart_toStartOf="@id/messageThumbnailView"
app:layout_constraintTop_toTopOf="@id/messageThumbnailView"
tools:visibility="visible" />


<include
android:id="@+id/messageMediaUploadProgressLayout"
layout="@layout/media_upload_download_progress_layout"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/messageThumbnailView"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,8 +3,6 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">


@ -13,8 +11,6 @@
layout="@layout/vector_message_merge_avatar_list" layout="@layout/vector_message_merge_avatar_list"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="64dp"
android:layout_marginLeft="64dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"

View File

@ -1,38 +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:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="16dp">

<ImageView
android:id="@+id/itemNoticeAvatarView"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="56dp"
android:layout_marginLeft="56dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/itemNoticeTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:textColor="@color/slate_grey"
android:textSize="14sp"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/itemNoticeAvatarView"
app:layout_constraintTop_toTopOf="@+id/itemNoticeAvatarView"
tools:text="Mon item" />

</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="horizontal"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/itemNoticeAvatarView"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />

<TextView
android:layout_gravity="top"
android:id="@+id/itemNoticeTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:textColor="@color/slate_grey"
android:textSize="14sp"
android:textStyle="italic"
tools:text="Jhon doe changed their avatar" />

</LinearLayout>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/messageTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/dark_grey"
android:textSize="14sp"
tools:text="Alright finished work, heading there in about 20 mins…Ping me when youre outside" />

View File

@ -246,4 +246,25 @@
<item name="android:textColorTertiary">@color/riot_tertiary_text_color_status</item> <item name="android:textColorTertiary">@color/riot_tertiary_text_color_status</item>
</style> </style>



<style name="TimelineContentStubBaseParams">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginStart">8dp</item>
<item name="android:layout_marginLeft">8dp</item>
<item name="android:layout_marginBottom">8dp</item>
<item name="android:layout_marginTop">4dp</item>
<item name="layout_constraintBottom_toBottomOf">parent</item>
<item name="layout_constraintEnd_toEndOf">parent</item>
<item name="layout_constraintStart_toEndOf">@id/messageStartGuideline</item>
</style>

<style name="TimelineContentStubNoInfoLayoutParams" parent="TimelineContentStubBaseParams">
<item name="layout_constraintTop_toTopOf">parent</item>
</style>


<style name="TimelineContentStubLayoutParams" parent="TimelineContentStubBaseParams">
<item name="layout_constraintTop_toBottomOf">@id/messageMemberNameView</item>
</style>
</resources> </resources>