Adjust colors for avatar and display names + start handling video in timeline
This commit is contained in:
parent
c38a601bcc
commit
9c9c09db2b
|
@ -31,6 +31,7 @@ class AutocompleteUserController : TypedEpoxyController<List<User>>() {
|
||||||
data.forEach { user ->
|
data.forEach { user ->
|
||||||
autocompleteUserItem {
|
autocompleteUserItem {
|
||||||
id(user.userId)
|
id(user.userId)
|
||||||
|
userId(user.userId)
|
||||||
name(user.displayName)
|
name(user.displayName)
|
||||||
avatarUrl(user.avatarUrl)
|
avatarUrl(user.avatarUrl)
|
||||||
clickListener { _ ->
|
clickListener { _ ->
|
||||||
|
|
|
@ -29,18 +29,15 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
@EpoxyModelClass(layout = R.layout.item_autocomplete_user)
|
@EpoxyModelClass(layout = R.layout.item_autocomplete_user)
|
||||||
abstract class AutocompleteUserItem : VectorEpoxyModel<AutocompleteUserItem.Holder>() {
|
abstract class AutocompleteUserItem : VectorEpoxyModel<AutocompleteUserItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute var name: String? = null
|
||||||
var name: String? = null
|
@EpoxyAttribute var userId: String = ""
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
var avatarUrl: String? = null
|
@EpoxyAttribute var clickListener: View.OnClickListener? = null
|
||||||
@EpoxyAttribute
|
|
||||||
var clickListener: View.OnClickListener? = null
|
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
holder.view.setOnClickListener(clickListener)
|
holder.view.setOnClickListener(clickListener)
|
||||||
|
|
||||||
holder.nameView.text = name
|
holder.nameView.text = name
|
||||||
AvatarRenderer.render(avatarUrl, name, holder.avatarImageView)
|
AvatarRenderer.render(avatarUrl, userId, name, holder.avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
|
|
@ -29,7 +29,6 @@ import com.bumptech.glide.request.target.Target
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.MatrixPatterns
|
import im.vector.matrix.android.api.MatrixPatterns
|
||||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.glide.GlideApp
|
import im.vector.riotredesign.core.glide.GlideApp
|
||||||
|
@ -44,39 +43,41 @@ object AvatarRenderer {
|
||||||
|
|
||||||
private const val THUMBNAIL_SIZE = 250
|
private const val THUMBNAIL_SIZE = 250
|
||||||
|
|
||||||
@UiThread
|
private val AVATAR_COLOR_LIST = listOf(
|
||||||
fun render(roomMember: RoomMember, imageView: ImageView) {
|
R.color.avatar_color_1,
|
||||||
render(roomMember.avatarUrl, roomMember.displayName, imageView)
|
R.color.avatar_color_2,
|
||||||
}
|
R.color.avatar_color_3
|
||||||
|
)
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
fun render(roomSummary: RoomSummary, imageView: ImageView) {
|
fun render(roomSummary: RoomSummary, imageView: ImageView) {
|
||||||
render(roomSummary.avatarUrl, roomSummary.displayName, imageView)
|
render(roomSummary.avatarUrl, roomSummary.roomId, roomSummary.displayName, imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
fun render(avatarUrl: String?, name: String?, imageView: ImageView) {
|
fun render(avatarUrl: String?, identifier: String, name: String?, imageView: ImageView) {
|
||||||
render(imageView.context, GlideApp.with(imageView), avatarUrl, name, DrawableImageViewTarget(imageView))
|
render(imageView.context, GlideApp.with(imageView), avatarUrl, identifier, name, DrawableImageViewTarget(imageView))
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
fun render(context: Context,
|
fun render(context: Context,
|
||||||
glideRequest: GlideRequests,
|
glideRequest: GlideRequests,
|
||||||
avatarUrl: String?,
|
avatarUrl: String?,
|
||||||
|
identifier: String,
|
||||||
name: String?,
|
name: String?,
|
||||||
target: Target<Drawable>) {
|
target: Target<Drawable>) {
|
||||||
if (name.isNullOrEmpty()) {
|
if (name.isNullOrEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val placeholder = getPlaceholderDrawable(context, name)
|
val placeholder = getPlaceholderDrawable(context, identifier, name)
|
||||||
buildGlideRequest(glideRequest, avatarUrl)
|
buildGlideRequest(glideRequest, avatarUrl)
|
||||||
.placeholder(placeholder)
|
.placeholder(placeholder)
|
||||||
.into(target)
|
.into(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnyThread
|
@AnyThread
|
||||||
fun getPlaceholderDrawable(context: Context, text: String): Drawable {
|
fun getPlaceholderDrawable(context: Context, identifier: String, text: String): Drawable {
|
||||||
val avatarColor = ContextCompat.getColor(context, R.color.pale_teal)
|
val avatarColor = ContextCompat.getColor(context, getAvatarColor(identifier))
|
||||||
return if (text.isEmpty()) {
|
return if (text.isEmpty()) {
|
||||||
TextDrawable.builder().buildRound("", avatarColor)
|
TextDrawable.builder().buildRound("", avatarColor)
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,9 +88,21 @@ object AvatarRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE API *********************************************************************************
|
// PRIVATE API *********************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
private fun getAvatarColor(text: String? = null): Int {
|
||||||
|
var colorIndex: Long = 0
|
||||||
|
if (!text.isNullOrEmpty()) {
|
||||||
|
var sum: Long = 0
|
||||||
|
for (i in 0 until text.length) {
|
||||||
|
sum += text[i].toLong()
|
||||||
|
}
|
||||||
|
colorIndex = sum % AVATAR_COLOR_LIST.size
|
||||||
|
}
|
||||||
|
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()
|
||||||
.resolveThumbnail(avatarUrl, THUMBNAIL_SIZE, THUMBNAIL_SIZE, ContentUrlResolver.ThumbnailMethod.SCALE)
|
.resolveThumbnail(avatarUrl, THUMBNAIL_SIZE, THUMBNAIL_SIZE, ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||||
|
|
|
@ -35,6 +35,7 @@ class GroupSummaryController : TypedEpoxyController<GroupListViewState>() {
|
||||||
val isSelected = groupSummary.groupId == selected?.groupId
|
val isSelected = groupSummary.groupId == selected?.groupId
|
||||||
groupSummaryItem {
|
groupSummaryItem {
|
||||||
id(groupSummary.groupId)
|
id(groupSummary.groupId)
|
||||||
|
groupId(groupSummary.groupId)
|
||||||
groupName(groupSummary.displayName)
|
groupName(groupSummary.displayName)
|
||||||
selected(isSelected)
|
selected(isSelected)
|
||||||
avatarUrl(groupSummary.avatarUrl)
|
avatarUrl(groupSummary.avatarUrl)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>() {
|
abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute lateinit var groupName: CharSequence
|
@EpoxyAttribute lateinit var groupName: CharSequence
|
||||||
|
@EpoxyAttribute lateinit var groupId: String
|
||||||
@EpoxyAttribute var avatarUrl: String? = null
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
@EpoxyAttribute var selected: Boolean = false
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||||
|
@ -37,7 +38,7 @@ abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>() {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
holder.rootView.isSelected = selected
|
holder.rootView.isSelected = selected
|
||||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
AvatarRenderer.render(avatarUrl, groupName.toString(), holder.avatarImageView)
|
AvatarRenderer.render(avatarUrl, groupId, groupName.toString(), holder.avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
|
|
@ -37,6 +37,8 @@ import com.otaliastudios.autocomplete.Autocomplete
|
||||||
import com.otaliastudios.autocomplete.AutocompleteCallback
|
import com.otaliastudios.autocomplete.AutocompleteCallback
|
||||||
import com.otaliastudios.autocomplete.CharPolicy
|
import com.otaliastudios.autocomplete.CharPolicy
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
|
@ -65,7 +67,7 @@ import im.vector.riotredesign.features.home.room.detail.composer.TextComposerVie
|
||||||
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.EndlessRecyclerViewScrollListener
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
|
||||||
import im.vector.riotredesign.features.html.PillImageSpan
|
import im.vector.riotredesign.features.html.PillImageSpan
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||||
import im.vector.riotredesign.features.media.MediaViewerActivity
|
import im.vector.riotredesign.features.media.MediaViewerActivity
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||||
|
@ -379,11 +381,16 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
||||||
roomDetailViewModel.process(RoomDetailActions.EventDisplayed(event))
|
roomDetailViewModel.process(RoomDetailActions.EventDisplayed(event))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaClicked(mediaData: MediaContentRenderer.Data, view: View) {
|
override fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) {
|
||||||
val intent = MediaViewerActivity.newIntent(vectorBaseActivity, mediaData)
|
val intent = MediaViewerActivity.newIntent(vectorBaseActivity, mediaData)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: ImageContentRenderer.Data, view: View) {
|
||||||
|
//TODO handle
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// AutocompleteUserPresenter.Callback
|
// AutocompleteUserPresenter.Callback
|
||||||
|
|
||||||
override fun onQueryUsers(query: CharSequence?) {
|
override fun onQueryUsers(query: CharSequence?) {
|
||||||
|
|
|
@ -25,15 +25,21 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.airbnb.epoxy.EpoxyController
|
import com.airbnb.epoxy.EpoxyController
|
||||||
import com.airbnb.epoxy.EpoxyModel
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
import com.airbnb.epoxy.VisibilityState
|
import com.airbnb.epoxy.VisibilityState
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.core.epoxy.LoadingItemModel_
|
import im.vector.riotredesign.core.epoxy.LoadingItemModel_
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotredesign.core.extensions.localDateTime
|
import im.vector.riotredesign.core.extensions.localDateTime
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.*
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineAsyncHelper
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.nextDisplayableEvent
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||||
|
|
||||||
class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
||||||
private val timelineItemFactory: TimelineItemFactory,
|
private val timelineItemFactory: TimelineItemFactory,
|
||||||
|
@ -44,7 +50,8 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onEventVisible(event: TimelineEvent)
|
fun onEventVisible(event: TimelineEvent)
|
||||||
fun onUrlClicked(url: String)
|
fun onUrlClicked(url: String)
|
||||||
fun onMediaClicked(mediaData: MediaContentRenderer.Data, view: View)
|
fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View)
|
||||||
|
fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: ImageContentRenderer.Data, view: View)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val modelCache = arrayListOf<List<EpoxyModel<*>>>()
|
private val modelCache = arrayListOf<List<EpoxyModel<*>>>()
|
||||||
|
|
|
@ -28,7 +28,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageEmoteConte
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||||
import im.vector.matrix.android.api.session.room.send.SendState
|
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
|
@ -40,13 +40,13 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.Timeline
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem_
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem_
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageItem
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageVideoItem
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageItem_
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageVideoItem_
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_
|
||||||
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
import im.vector.riotredesign.features.html.EventHtmlRenderer
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
|
|
||||||
class MessageItemFactory(private val colorProvider: ColorProvider,
|
class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||||
|
@ -79,15 +79,22 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||||
val avatarUrl = roomMember?.avatarUrl
|
val avatarUrl = roomMember?.avatarUrl
|
||||||
val memberName = roomMember?.displayName ?: event.root.sender ?: ""
|
val memberName = roomMember?.displayName ?: event.root.sender ?: ""
|
||||||
val formattedMemberName = span(memberName) {
|
val formattedMemberName = span(memberName) {
|
||||||
textColor = colorProvider.getColor(colorIndexForSender(memberName))
|
textColor = colorProvider.getColor(getColorFor(event.root.sender ?: ""))
|
||||||
}
|
}
|
||||||
val informationData = MessageInformationData(time, avatarUrl, formattedMemberName, showInformation)
|
val informationData = MessageInformationData(eventId = eventId,
|
||||||
|
senderId = event.root.sender ?: "",
|
||||||
|
sendState = event.sendState,
|
||||||
|
time = time,
|
||||||
|
avatarUrl = avatarUrl,
|
||||||
|
memberName = formattedMemberName,
|
||||||
|
showInformation = showInformation)
|
||||||
|
|
||||||
return when (messageContent) {
|
return when (messageContent) {
|
||||||
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, callback)
|
is MessageEmoteContent -> buildEmoteMessageItem(messageContent, informationData, callback)
|
||||||
is MessageTextContent -> buildTextMessageItem(event.sendState, messageContent, informationData, callback)
|
is MessageTextContent -> buildTextMessageItem(messageContent, informationData, callback)
|
||||||
is MessageImageContent -> buildImageMessageItem(eventId, messageContent, informationData, callback)
|
is MessageImageContent -> buildImageMessageItem(messageContent, informationData, callback)
|
||||||
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback)
|
is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback)
|
||||||
|
is MessageVideoContent -> buildVideoMessageItem(messageContent, informationData, callback)
|
||||||
else -> buildNotHandledMessageItem(messageContent)
|
else -> buildNotHandledMessageItem(messageContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,31 +104,49 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||||
return DefaultItem_().text(text)
|
return DefaultItem_().text(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildImageMessageItem(eventId: String,
|
private fun buildImageMessageItem(messageContent: MessageImageContent,
|
||||||
messageContent: MessageImageContent,
|
|
||||||
informationData: MessageInformationData,
|
informationData: MessageInformationData,
|
||||||
callback: TimelineEventController.Callback?): MessageImageItem? {
|
callback: TimelineEventController.Callback?): MessageImageVideoItem? {
|
||||||
|
|
||||||
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
||||||
val data = MediaContentRenderer.Data(
|
val data = ImageContentRenderer.Data(
|
||||||
messageContent.body,
|
filename = messageContent.body,
|
||||||
url = messageContent.url,
|
url = messageContent.url,
|
||||||
height = messageContent.info?.height,
|
height = messageContent.info?.height,
|
||||||
maxHeight = maxHeight,
|
maxHeight = maxHeight,
|
||||||
width = messageContent.info?.width,
|
width = messageContent.info?.width,
|
||||||
maxWidth = maxWidth,
|
maxWidth = maxWidth,
|
||||||
rotation = messageContent.info?.rotation,
|
orientation = messageContent.info?.orientation,
|
||||||
orientation = messageContent.info?.orientation
|
rotation = messageContent.info?.rotation
|
||||||
)
|
)
|
||||||
return MessageImageItem_()
|
return MessageImageVideoItem_()
|
||||||
.eventId(eventId)
|
.playable(messageContent.info?.mimeType == "image/gif")
|
||||||
.informationData(informationData)
|
.informationData(informationData)
|
||||||
.mediaData(data)
|
.mediaData(data)
|
||||||
.clickListener { view -> callback?.onMediaClicked(data, view) }
|
.clickListener { view -> callback?.onImageMessageClicked(messageContent, data, view) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildTextMessageItem(sendState: SendState,
|
private fun buildVideoMessageItem(messageContent: MessageVideoContent,
|
||||||
messageContent: MessageTextContent,
|
informationData: MessageInformationData,
|
||||||
|
callback: TimelineEventController.Callback?): MessageImageVideoItem? {
|
||||||
|
|
||||||
|
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
||||||
|
val data = ImageContentRenderer.Data(
|
||||||
|
filename = messageContent.body,
|
||||||
|
url = messageContent.info?.thumbnailUrl,
|
||||||
|
height = messageContent.info?.height,
|
||||||
|
maxHeight = maxHeight,
|
||||||
|
width = messageContent.info?.width,
|
||||||
|
maxWidth = maxWidth
|
||||||
|
)
|
||||||
|
return MessageImageVideoItem_()
|
||||||
|
.playable(true)
|
||||||
|
.informationData(informationData)
|
||||||
|
.mediaData(data)
|
||||||
|
.clickListener { view -> callback?.onVideoMessageClicked(messageContent, data, view) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildTextMessageItem(messageContent: MessageTextContent,
|
||||||
informationData: MessageInformationData,
|
informationData: MessageInformationData,
|
||||||
callback: TimelineEventController.Callback?): MessageTextItem? {
|
callback: TimelineEventController.Callback?): MessageTextItem? {
|
||||||
|
|
||||||
|
@ -129,15 +154,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||||
htmlRenderer.render(it)
|
htmlRenderer.render(it)
|
||||||
} ?: messageContent.body
|
} ?: messageContent.body
|
||||||
|
|
||||||
val textColor = if (sendState.isSent()) {
|
val linkifiedBody = linkifyBody(bodyToUse, callback)
|
||||||
R.color.dark_grey
|
|
||||||
} else {
|
|
||||||
R.color.brown_grey
|
|
||||||
}
|
|
||||||
val formattedBody = span(bodyToUse) {
|
|
||||||
this.textColor = colorProvider.getColor(textColor)
|
|
||||||
}
|
|
||||||
val linkifiedBody = linkifyBody(formattedBody, callback)
|
|
||||||
return MessageTextItem_()
|
return MessageTextItem_()
|
||||||
.message(linkifiedBody)
|
.message(linkifiedBody)
|
||||||
.informationData(informationData)
|
.informationData(informationData)
|
||||||
|
@ -184,8 +201,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||||
return spannable
|
return spannable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Based on riot-web implementation
|
||||||
@ColorRes
|
@ColorRes
|
||||||
private fun colorIndexForSender(sender: String): Int {
|
private fun getColorFor(sender: String): Int {
|
||||||
var hash = 0
|
var hash = 0
|
||||||
var i = 0
|
var i = 0
|
||||||
var chr: Char
|
var chr: Char
|
||||||
|
@ -210,6 +228,4 @@ class MessageItemFactory(private val colorProvider: ColorProvider,
|
||||||
else -> R.color.username_8
|
else -> R.color.username_8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -25,7 +25,7 @@ import android.widget.TextView
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object ContentUploadStateTrackerBinder {
|
object ContentUploadStateTrackerBinder {
|
||||||
|
@ -33,7 +33,7 @@ object ContentUploadStateTrackerBinder {
|
||||||
private val updateListeners = mutableMapOf<String, ContentUploadStateTracker.UpdateListener>()
|
private val updateListeners = mutableMapOf<String, ContentUploadStateTracker.UpdateListener>()
|
||||||
|
|
||||||
fun bind(eventId: String,
|
fun bind(eventId: String,
|
||||||
mediaData: MediaContentRenderer.Data,
|
mediaData: ImageContentRenderer.Data,
|
||||||
progressLayout: ViewGroup) {
|
progressLayout: ViewGroup) {
|
||||||
|
|
||||||
Matrix.getInstance().currentSession?.also { session ->
|
Matrix.getInstance().currentSession?.also { session ->
|
||||||
|
@ -56,7 +56,7 @@ object ContentUploadStateTrackerBinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
||||||
private val mediaData: MediaContentRenderer.Data) : ContentUploadStateTracker.UpdateListener {
|
private val mediaData: ImageContentRenderer.Data) : ContentUploadStateTracker.UpdateListener {
|
||||||
|
|
||||||
override fun onUpdate(state: ContentUploadStateTracker.State) {
|
override fun onUpdate(state: ContentUploadStateTracker.State) {
|
||||||
when (state) {
|
when (state) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : VectorEpoxyModel<H>()
|
||||||
holder.timeView.visibility = View.VISIBLE
|
holder.timeView.visibility = View.VISIBLE
|
||||||
holder.timeView.text = informationData.time
|
holder.timeView.text = informationData.time
|
||||||
holder.memberNameView.text = informationData.memberName
|
holder.memberNameView.text = informationData.memberName
|
||||||
AvatarRenderer.render(informationData.avatarUrl, informationData.memberName?.toString(), holder.avatarImageView)
|
AvatarRenderer.render(informationData.avatarUrl, informationData.senderId, informationData.memberName?.toString(), holder.avatarImageView)
|
||||||
} else {
|
} else {
|
||||||
holder.avatarImageView.visibility = View.GONE
|
holder.avatarImageView.visibility = View.GONE
|
||||||
holder.memberNameView.visibility = View.GONE
|
holder.memberNameView.visibility = View.GONE
|
||||||
|
@ -43,6 +43,11 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : VectorEpoxyModel<H>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun View.renderSendState() {
|
||||||
|
isClickable = informationData.sendState.isSent()
|
||||||
|
alpha = if (informationData.sendState.isSent()) 1f else 0.5f
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Holder : VectorEpoxyHolder() {
|
abstract class Holder : VectorEpoxyHolder() {
|
||||||
abstract val avatarImageView: ImageView
|
abstract val avatarImageView: ImageView
|
||||||
abstract val memberNameView: TextView
|
abstract val memberNameView: TextView
|
||||||
|
|
|
@ -24,27 +24,27 @@ 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.MediaContentRenderer
|
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_image_message)
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_image_video_message)
|
||||||
abstract class MessageImageItem : AbsMessageItem<MessageImageItem.Holder>() {
|
abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute lateinit var mediaData: MediaContentRenderer.Data
|
@EpoxyAttribute lateinit var mediaData: ImageContentRenderer.Data
|
||||||
@EpoxyAttribute lateinit var eventId: String
|
|
||||||
@EpoxyAttribute override lateinit var informationData: MessageInformationData
|
@EpoxyAttribute override lateinit var informationData: MessageInformationData
|
||||||
|
@EpoxyAttribute var playable: Boolean = false
|
||||||
@EpoxyAttribute var clickListener: View.OnClickListener? = null
|
@EpoxyAttribute var clickListener: View.OnClickListener? = null
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
MediaContentRenderer.render(mediaData, MediaContentRenderer.Mode.THUMBNAIL, holder.imageView)
|
ImageContentRenderer.render(mediaData, ImageContentRenderer.Mode.THUMBNAIL, holder.imageView)
|
||||||
ContentUploadStateTrackerBinder.bind(eventId, mediaData, holder.progressLayout)
|
ContentUploadStateTrackerBinder.bind(informationData.eventId, mediaData, holder.progressLayout)
|
||||||
holder.imageView.setOnClickListener(clickListener)
|
holder.imageView.setOnClickListener(clickListener)
|
||||||
holder.imageView.isEnabled = !mediaData.isLocalFile()
|
holder.imageView.renderSendState()
|
||||||
holder.imageView.alpha = if (mediaData.isLocalFile()) 0.5f else 1f
|
holder.playContentView.visibility = if (playable) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unbind(holder: Holder) {
|
override fun unbind(holder: Holder) {
|
||||||
ContentUploadStateTrackerBinder.unbind(eventId)
|
ContentUploadStateTrackerBinder.unbind(informationData.eventId)
|
||||||
super.unbind(holder)
|
super.unbind(holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +52,9 @@ abstract class MessageImageItem : AbsMessageItem<MessageImageItem.Holder>() {
|
||||||
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
override val avatarImageView by bind<ImageView>(R.id.messageAvatarImageView)
|
||||||
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
override val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
||||||
override val timeView by bind<TextView>(R.id.messageTimeView)
|
override val timeView by bind<TextView>(R.id.messageTimeView)
|
||||||
val progressLayout by bind<ViewGroup>(R.id.messageImageUploadProgressLayout)
|
val progressLayout by bind<ViewGroup>(R.id.messageMediaUploadProgressLayout)
|
||||||
val imageView by bind<ImageView>(R.id.messageImageView)
|
val imageView by bind<ImageView>(R.id.messageThumbnailView)
|
||||||
|
val playContentView by bind<ImageView>(R.id.messageMediaPlayView)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -16,7 +16,12 @@
|
||||||
|
|
||||||
package im.vector.riotredesign.features.home.room.detail.timeline.item
|
package im.vector.riotredesign.features.home.room.detail.timeline.item
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
|
|
||||||
data class MessageInformationData(
|
data class MessageInformationData(
|
||||||
|
val eventId: String,
|
||||||
|
val senderId: String,
|
||||||
|
val sendState: SendState,
|
||||||
val time: CharSequence? = null,
|
val time: CharSequence? = null,
|
||||||
val avatarUrl: String?,
|
val avatarUrl: String?,
|
||||||
val memberName: CharSequence? = null,
|
val memberName: CharSequence? = null,
|
||||||
|
|
|
@ -45,6 +45,7 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
|
||||||
TextViewCompat.getTextMetricsParams(holder.messageView),
|
TextViewCompat.getTextMetricsParams(holder.messageView),
|
||||||
null)
|
null)
|
||||||
holder.messageView.setTextFuture(textFuture)
|
holder.messageView.setTextFuture(textFuture)
|
||||||
|
holder.messageView.renderSendState()
|
||||||
findPillsAndProcess { it.bind(holder.messageView) }
|
findPillsAndProcess { it.bind(holder.messageView) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,12 @@ abstract class NoticeItem : VectorEpoxyModel<NoticeItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute var noticeText: CharSequence? = null
|
@EpoxyAttribute var noticeText: CharSequence? = null
|
||||||
@EpoxyAttribute var avatarUrl: String? = null
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
|
@EpoxyAttribute var userId: String = ""
|
||||||
@EpoxyAttribute var memberName: CharSequence? = null
|
@EpoxyAttribute var memberName: CharSequence? = null
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
holder.noticeTextView.text = noticeText
|
holder.noticeTextView.text = noticeText
|
||||||
AvatarRenderer.render(avatarUrl, memberName?.toString(), holder.avatarImageView)
|
AvatarRenderer.render(avatarUrl, userId, memberName?.toString(), holder.avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
|
|
@ -79,6 +79,7 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
||||||
|
|
||||||
roomSummaryItem {
|
roomSummaryItem {
|
||||||
id(roomSummary.roomId)
|
id(roomSummary.roomId)
|
||||||
|
roomId(roomSummary.roomId)
|
||||||
roomName(roomSummary.displayName)
|
roomName(roomSummary.displayName)
|
||||||
avatarUrl(roomSummary.avatarUrl)
|
avatarUrl(roomSummary.avatarUrl)
|
||||||
selected(isSelected)
|
selected(isSelected)
|
||||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute lateinit var roomName: CharSequence
|
@EpoxyAttribute lateinit var roomName: CharSequence
|
||||||
|
@EpoxyAttribute lateinit var roomId: String
|
||||||
@EpoxyAttribute var avatarUrl: String? = null
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
@EpoxyAttribute var selected: Boolean = false
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
@EpoxyAttribute var unreadCount: Int = 0
|
@EpoxyAttribute var unreadCount: Int = 0
|
||||||
|
@ -44,7 +45,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||||
holder.rootView.isChecked = selected
|
holder.rootView.isChecked = selected
|
||||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||||
holder.titleView.text = roomName
|
holder.titleView.text = roomName
|
||||||
AvatarRenderer.render(avatarUrl, roomName.toString(), holder.avatarImageView)
|
AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
|
|
@ -52,7 +52,7 @@ class PillImageSpan(private val glideRequests: GlideRequests,
|
||||||
@UiThread
|
@UiThread
|
||||||
fun bind(textView: TextView) {
|
fun bind(textView: TextView) {
|
||||||
tv = WeakReference(textView)
|
tv = WeakReference(textView)
|
||||||
AvatarRenderer.render(context, glideRequests, user?.avatarUrl, displayName, target)
|
AvatarRenderer.render(context, glideRequests, user?.avatarUrl, userId, displayName, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplacementSpan *****************************************************************************
|
// ReplacementSpan *****************************************************************************
|
||||||
|
@ -105,7 +105,7 @@ class PillImageSpan(private val glideRequests: GlideRequests,
|
||||||
textStartPadding = textPadding
|
textStartPadding = textPadding
|
||||||
setChipMinHeightResource(R.dimen.pill_min_height)
|
setChipMinHeightResource(R.dimen.pill_min_height)
|
||||||
setChipIconSizeResource(R.dimen.pill_avatar_size)
|
setChipIconSizeResource(R.dimen.pill_avatar_size)
|
||||||
chipIcon = AvatarRenderer.getPlaceholderDrawable(context, displayName)
|
chipIcon = AvatarRenderer.getPlaceholderDrawable(context, userId, displayName)
|
||||||
setBounds(0, 0, intrinsicWidth, intrinsicHeight)
|
setBounds(0, 0, intrinsicWidth, intrinsicHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import im.vector.riotredesign.core.glide.GlideApp
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object MediaContentRenderer {
|
object ImageContentRenderer {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Data(
|
data class Data(
|
||||||
|
@ -37,8 +37,8 @@ object MediaContentRenderer {
|
||||||
val maxHeight: Int,
|
val maxHeight: Int,
|
||||||
val width: Int?,
|
val width: Int?,
|
||||||
val maxWidth: Int,
|
val maxWidth: Int,
|
||||||
val orientation: Int?,
|
val orientation: Int? = null,
|
||||||
val rotation: Int?
|
val rotation: Int? = null
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
fun isLocalFile(): Boolean {
|
fun isLocalFile(): Boolean {
|
||||||
|
@ -66,6 +66,7 @@ object MediaContentRenderer {
|
||||||
GlideApp
|
GlideApp
|
||||||
.with(imageView)
|
.with(imageView)
|
||||||
.load(resolvedUrl)
|
.load(resolvedUrl)
|
||||||
|
.dontAnimate()
|
||||||
.thumbnail(0.3f)
|
.thumbnail(0.3f)
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
}
|
}
|
||||||
|
@ -73,9 +74,6 @@ object MediaContentRenderer {
|
||||||
fun render(data: Data, imageView: BigImageView) {
|
fun render(data: Data, imageView: BigImageView) {
|
||||||
val (width, height) = processSize(data, Mode.THUMBNAIL)
|
val (width, height) = processSize(data, Mode.THUMBNAIL)
|
||||||
val contentUrlResolver = Matrix.getInstance().currentSession!!.contentUrlResolver()
|
val contentUrlResolver = Matrix.getInstance().currentSession!!.contentUrlResolver()
|
||||||
if (data.isLocalFile()) {
|
|
||||||
imageView.showImage(Uri.parse(data.url))
|
|
||||||
} else {
|
|
||||||
val fullSize = contentUrlResolver.resolveFullSize(data.url)
|
val fullSize = contentUrlResolver.resolveFullSize(data.url)
|
||||||
val thumbnail = contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE)
|
val thumbnail = contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||||
imageView.showImage(
|
imageView.showImage(
|
||||||
|
@ -83,7 +81,6 @@ object MediaContentRenderer {
|
||||||
Uri.parse(fullSize)
|
Uri.parse(fullSize)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun processSize(data: Data, mode: Mode): Pair<Int, Int> {
|
private fun processSize(data: Data, mode: Mode): Pair<Int, Int> {
|
||||||
val maxImageWidth = data.maxWidth
|
val maxImageWidth = data.maxWidth
|
|
@ -33,18 +33,18 @@ class MediaViewerActivity : VectorBaseActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(im.vector.riotredesign.R.layout.activity_media_viewer)
|
setContentView(im.vector.riotredesign.R.layout.activity_media_viewer)
|
||||||
val mediaData = intent.getParcelableExtra<MediaContentRenderer.Data>(EXTRA_MEDIA_DATA)
|
val mediaData = intent.getParcelableExtra<ImageContentRenderer.Data>(EXTRA_MEDIA_DATA)
|
||||||
if (mediaData.url.isNullOrEmpty()) {
|
if (mediaData.url.isNullOrEmpty()) {
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
configureToolbar(mediaViewerToolbar, mediaData)
|
configureToolbar(mediaViewerToolbar, mediaData)
|
||||||
mediaViewerImageView.setImageViewFactory(GlideImageViewFactory())
|
mediaViewerImageView.setImageViewFactory(GlideImageViewFactory())
|
||||||
mediaViewerImageView.setProgressIndicator(ProgressPieIndicator())
|
mediaViewerImageView.setProgressIndicator(ProgressPieIndicator())
|
||||||
MediaContentRenderer.render(mediaData, mediaViewerImageView)
|
ImageContentRenderer.render(mediaData, mediaViewerImageView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureToolbar(toolbar: Toolbar, mediaData: MediaContentRenderer.Data) {
|
private fun configureToolbar(toolbar: Toolbar, mediaData: ImageContentRenderer.Data) {
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
supportActionBar?.apply {
|
supportActionBar?.apply {
|
||||||
title = mediaData.filename
|
title = mediaData.filename
|
||||||
|
@ -57,7 +57,7 @@ class MediaViewerActivity : VectorBaseActivity() {
|
||||||
|
|
||||||
private const val EXTRA_MEDIA_DATA = "EXTRA_MEDIA_DATA"
|
private const val EXTRA_MEDIA_DATA = "EXTRA_MEDIA_DATA"
|
||||||
|
|
||||||
fun newIntent(context: Context, mediaData: MediaContentRenderer.Data): Intent {
|
fun newIntent(context: Context, mediaData: ImageContentRenderer.Data): Intent {
|
||||||
return Intent(context, MediaViewerActivity::class.java).apply {
|
return Intent(context, MediaViewerActivity::class.java).apply {
|
||||||
putExtra(EXTRA_MEDIA_DATA, mediaData)
|
putExtra(EXTRA_MEDIA_DATA, mediaData)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,19 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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"
|
<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"
|
||||||
|
@ -43,6 +58,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
android:textColor="@color/brown_grey"
|
android:textColor="@color/brown_grey"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
@ -50,7 +66,7 @@
|
||||||
tools:text="@tools:sample/date/hhmm" />
|
tools:text="@tools:sample/date/hhmm" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/messageImageView"
|
android:id="@+id/messageThumbnailView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginStart="64dp"
|
android:layout_marginStart="64dp"
|
||||||
|
@ -59,13 +75,28 @@
|
||||||
android:layout_marginEnd="32dp"
|
android:layout_marginEnd="32dp"
|
||||||
android:layout_marginRight="32dp"
|
android:layout_marginRight="32dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0"
|
app:layout_constraintHorizontal_bias="0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/messageMemberNameView" />
|
app:layout_constraintTop_toBottomOf="@+id/messageMemberNameView"
|
||||||
|
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
|
<include
|
||||||
android:id="@+id/messageImageUploadProgressLayout"
|
android:id="@+id/messageMediaUploadProgressLayout"
|
||||||
layout="@layout/media_upload_download_progress_layout"
|
layout="@layout/media_upload_download_progress_layout"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="46dp"
|
android:layout_height="46dp"
|
||||||
|
@ -78,7 +109,7 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/messageImageView"
|
app:layout_constraintTop_toBottomOf="@+id/messageThumbnailView"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:textColor="@color/brown_grey"
|
android:textColor="@color/brown_grey"
|
||||||
|
android:duplicateParentState="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintTop_toTopOf="@id/messageMemberNameView"
|
app:layout_constraintTop_toTopOf="@id/messageMemberNameView"
|
||||||
|
@ -56,6 +57,7 @@
|
||||||
android:layout_marginStart="64dp"
|
android:layout_marginStart="64dp"
|
||||||
android:layout_marginLeft="64dp"
|
android:layout_marginLeft="64dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
android:textColor="@color/dark_grey"
|
android:textColor="@color/dark_grey"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
Loading…
Reference in New Issue