mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-28 14:08:44 +03:00
Render MSC2530 captions
Change-Id: I10f875121e90102a0518d9bd39d87b3daa68ef2e
This commit is contained in:
parent
3214c782bc
commit
58dd1dedc9
21 changed files with 192 additions and 23 deletions
|
@ -32,6 +32,7 @@ Here you can find some extra features and changes compared to Element Android (w
|
||||||
- Render inline images / custom emojis in the timeline
|
- Render inline images / custom emojis in the timeline
|
||||||
- Render image reactions
|
- Render image reactions
|
||||||
- Send freeform reactions
|
- Send freeform reactions
|
||||||
|
- Render media captions ([MSC2530](https://github.com/matrix-org/matrix-spec-proposals/pull/2530))
|
||||||
|
|
||||||
- Branding (name, app icon, links)
|
- Branding (name, app icon, links)
|
||||||
- Show a toast instead of a snackbar after copying text, in order to not block the input area right after copying
|
- Show a toast instead of a snackbar after copying text, in order to not block the input area right after copying
|
||||||
|
|
|
@ -45,6 +45,11 @@ data class MessageAudioContent(
|
||||||
*/
|
*/
|
||||||
@Json(name = "url") override val url: String? = null,
|
@Json(name = "url") override val url: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSC 2530: filename as filename, using body as caption instead
|
||||||
|
*/
|
||||||
|
@Json(name = "filename") override val filename: String? = null,
|
||||||
|
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@Json(name = "m.new_content") override val newContent: Content? = null,
|
@Json(name = "m.new_content") override val newContent: Content? = null,
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ data class MessageFileContent(
|
||||||
/**
|
/**
|
||||||
* The original filename of the uploaded file.
|
* The original filename of the uploaded file.
|
||||||
*/
|
*/
|
||||||
@Json(name = "filename") val filename: String? = null,
|
@Json(name = "filename") override val filename: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the file referred to in url.
|
* Information about the file referred to in url.
|
||||||
|
|
|
@ -45,6 +45,11 @@ data class MessageImageContent(
|
||||||
*/
|
*/
|
||||||
@Json(name = "url") override val url: String? = null,
|
@Json(name = "url") override val url: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSC 2530: filename as filename, using body as caption instead
|
||||||
|
*/
|
||||||
|
@Json(name = "filename") override val filename: String? = null,
|
||||||
|
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@Json(name = "m.new_content") override val newContent: Content? = null,
|
@Json(name = "m.new_content") override val newContent: Content? = null,
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,11 @@ data class MessageStickerContent(
|
||||||
*/
|
*/
|
||||||
@Json(name = "url") override val url: String? = null,
|
@Json(name = "url") override val url: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSC 2530: filename as filename, using body as caption instead
|
||||||
|
*/
|
||||||
|
@Json(name = "filename") override val filename: String? = null,
|
||||||
|
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@Json(name = "m.new_content") override val newContent: Content? = null,
|
@Json(name = "m.new_content") override val newContent: Content? = null,
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,11 @@ data class MessageVideoContent(
|
||||||
*/
|
*/
|
||||||
@Json(name = "url") override val url: String? = null,
|
@Json(name = "url") override val url: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSC 2530: filename as filename, using body as caption instead
|
||||||
|
*/
|
||||||
|
@Json(name = "filename") override val filename: String? = null,
|
||||||
|
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@Json(name = "m.new_content") override val newContent: Content? = null,
|
@Json(name = "m.new_content") override val newContent: Content? = null,
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,9 @@ interface MessageWithAttachmentContent : MessageContent {
|
||||||
val encryptedFileInfo: EncryptedFileInfo?
|
val encryptedFileInfo: EncryptedFileInfo?
|
||||||
|
|
||||||
val mimeType: String?
|
val mimeType: String?
|
||||||
|
|
||||||
|
// MSC 2530 adds filename for other media types than m.file as well
|
||||||
|
val filename: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,4 +43,6 @@ interface MessageWithAttachmentContent : MessageContent {
|
||||||
*/
|
*/
|
||||||
fun MessageWithAttachmentContent.getFileUrl() = encryptedFileInfo?.url ?: url
|
fun MessageWithAttachmentContent.getFileUrl() = encryptedFileInfo?.url ?: url
|
||||||
|
|
||||||
fun MessageWithAttachmentContent.getFileName() = (this as? MessageFileContent)?.getFileName() ?: body
|
fun MessageWithAttachmentContent.getFileName() = (this as? MessageFileContent)?.getFileName() ?: filename ?: body
|
||||||
|
|
||||||
|
fun MessageWithAttachmentContent.getCaption() = body.takeIf { filename != null && filename != it }
|
||||||
|
|
|
@ -108,6 +108,8 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.asMessageAudioEvent
|
import org.matrix.android.sdk.api.session.room.model.message.asMessageAudioEvent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getCaption
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
||||||
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
|
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
|
||||||
|
@ -285,7 +287,8 @@ class MessageItemFactory @Inject constructor(
|
||||||
|
|
||||||
return MessageAudioItem_()
|
return MessageAudioItem_()
|
||||||
.attributes(attributes)
|
.attributes(attributes)
|
||||||
.filename(messageContent.body)
|
.filename(messageContent.getFileName())
|
||||||
|
.caption(messageContent.getCaption())
|
||||||
.duration(messageContent.audioInfo?.duration ?: 0)
|
.duration(messageContent.audioInfo?.duration ?: 0)
|
||||||
.playbackControlButtonClickListener(playbackControlButtonClickListener)
|
.playbackControlButtonClickListener(playbackControlButtonClickListener)
|
||||||
.audioMessagePlaybackTracker(audioMessagePlaybackTracker)
|
.audioMessagePlaybackTracker(audioMessagePlaybackTracker)
|
||||||
|
@ -418,7 +421,8 @@ class MessageItemFactory @Inject constructor(
|
||||||
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
|
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
|
||||||
.contentDownloadStateTrackerBinder(contentDownloadStateTrackerBinder)
|
.contentDownloadStateTrackerBinder(contentDownloadStateTrackerBinder)
|
||||||
.highlighted(highlight)
|
.highlighted(highlight)
|
||||||
.filename(messageContent.body)
|
.filename(messageContent.getFileName())
|
||||||
|
.caption(messageContent.getCaption())
|
||||||
.iconRes(R.drawable.ic_paperclip)
|
.iconRes(R.drawable.ic_paperclip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +460,8 @@ class MessageItemFactory @Inject constructor(
|
||||||
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
||||||
val data = ImageContentRenderer.Data(
|
val data = ImageContentRenderer.Data(
|
||||||
eventId = informationData.eventId,
|
eventId = informationData.eventId,
|
||||||
filename = messageContent.body,
|
filename = messageContent.getFileName(),
|
||||||
|
caption = messageContent.getCaption(),
|
||||||
mimeType = messageContent.mimeType,
|
mimeType = messageContent.mimeType,
|
||||||
url = messageContent.getFileUrl(),
|
url = messageContent.getFileUrl(),
|
||||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
@ -505,7 +510,8 @@ class MessageItemFactory @Inject constructor(
|
||||||
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
val (maxWidth, maxHeight) = timelineMediaSizeProvider.getMaxSize()
|
||||||
val thumbnailData = ImageContentRenderer.Data(
|
val thumbnailData = ImageContentRenderer.Data(
|
||||||
eventId = informationData.eventId,
|
eventId = informationData.eventId,
|
||||||
filename = messageContent.body,
|
filename = messageContent.getFileName(),
|
||||||
|
caption = messageContent.getCaption(),
|
||||||
mimeType = messageContent.mimeType,
|
mimeType = messageContent.mimeType,
|
||||||
url = messageContent.videoInfo?.getThumbnailUrl(),
|
url = messageContent.videoInfo?.getThumbnailUrl(),
|
||||||
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
|
@ -522,7 +528,8 @@ class MessageItemFactory @Inject constructor(
|
||||||
|
|
||||||
val videoData = VideoContentRenderer.Data(
|
val videoData = VideoContentRenderer.Data(
|
||||||
eventId = informationData.eventId,
|
eventId = informationData.eventId,
|
||||||
filename = messageContent.body,
|
filename = messageContent.getFileName(),
|
||||||
|
caption = messageContent.getCaption(),
|
||||||
mimeType = messageContent.mimeType,
|
mimeType = messageContent.mimeType,
|
||||||
url = messageContent.getFileUrl(),
|
url = messageContent.getFileUrl(),
|
||||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
|
|
@ -23,6 +23,8 @@ import org.matrix.android.sdk.api.session.events.model.isVideoMessage
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getCaption
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
|
@ -33,7 +35,8 @@ fun TimelineEvent.buildImageContentRendererData(maxHeight: Int, generateMissingV
|
||||||
?.let { messageImageContent ->
|
?.let { messageImageContent ->
|
||||||
ImageContentRenderer.Data(
|
ImageContentRenderer.Data(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
filename = messageImageContent.body,
|
filename = messageImageContent.getFileName(),
|
||||||
|
caption = messageImageContent.getCaption(),
|
||||||
mimeType = messageImageContent.mimeType,
|
mimeType = messageImageContent.mimeType,
|
||||||
url = messageImageContent.getFileUrl(),
|
url = messageImageContent.getFileUrl(),
|
||||||
elementToDecrypt = messageImageContent.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = messageImageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
@ -49,7 +52,8 @@ fun TimelineEvent.buildImageContentRendererData(maxHeight: Int, generateMissingV
|
||||||
val videoInfo = messageVideoContent.videoInfo
|
val videoInfo = messageVideoContent.videoInfo
|
||||||
ImageContentRenderer.Data(
|
ImageContentRenderer.Data(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
filename = messageVideoContent.body,
|
filename = messageVideoContent.getFileName(),
|
||||||
|
caption = messageVideoContent.getCaption(),
|
||||||
mimeType = videoInfo?.thumbnailInfo?.mimeType,
|
mimeType = videoInfo?.thumbnailInfo?.mimeType,
|
||||||
url = videoInfo?.getThumbnailUrl(),
|
url = videoInfo?.getThumbnailUrl(),
|
||||||
elementToDecrypt = videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
|
|
|
@ -30,11 +30,14 @@ import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.ClickListener
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
import im.vector.app.core.epoxy.onClick
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
|
import im.vector.app.core.ui.views.FooteredTextView
|
||||||
import im.vector.app.core.utils.TextUtils
|
import im.vector.app.core.utils.TextUtils
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
|
import im.vector.app.features.home.room.detail.timeline.helper.AudioMessagePlaybackTracker
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
|
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
||||||
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.view.ScMessageBubbleWrapView
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
|
||||||
@EpoxyModelClass
|
@EpoxyModelClass
|
||||||
|
@ -43,6 +46,9 @@ abstract class MessageAudioItem : AbsMessageItem<MessageAudioItem.Holder>() {
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var filename: String = ""
|
var filename: String = ""
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var caption: String? = null
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var mxcUrl: String = ""
|
var mxcUrl: String = ""
|
||||||
|
|
||||||
|
@ -115,6 +121,7 @@ abstract class MessageAudioItem : AbsMessageItem<MessageAudioItem.Holder>() {
|
||||||
holder.fileSize.text = holder.rootLayout.context.getString(
|
holder.fileSize.text = holder.rootLayout.context.getString(
|
||||||
R.string.audio_message_file_size, formattedFileSize
|
R.string.audio_message_file_size, formattedFileSize
|
||||||
)
|
)
|
||||||
|
holder.captionView.setTextOrHide(caption)
|
||||||
holder.mainLayout.contentDescription = holder.rootLayout.context.getString(
|
holder.mainLayout.contentDescription = holder.rootLayout.context.getString(
|
||||||
R.string.a11y_audio_message_item, filename, durationContentDescription, formattedFileSize
|
R.string.a11y_audio_message_item, filename, durationContentDescription, formattedFileSize
|
||||||
)
|
)
|
||||||
|
@ -195,6 +202,19 @@ abstract class MessageAudioItem : AbsMessageItem<MessageAudioItem.Holder>() {
|
||||||
audioMessagePlaybackTracker.untrack(attributes.informationData.eventId)
|
audioMessagePlaybackTracker.untrack(attributes.informationData.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hasCaption() = !caption.isNullOrBlank()
|
||||||
|
|
||||||
|
override fun allowFooterOverlay(holder: Holder, bubbleWrapView: ScMessageBubbleWrapView): Boolean = hasCaption()
|
||||||
|
|
||||||
|
override fun needsFooterReservation(): Boolean {
|
||||||
|
return hasCaption()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reserveFooterSpace(holder: Holder, width: Int, height: Int) {
|
||||||
|
holder.captionView.footerWidth = width
|
||||||
|
holder.captionView.footerHeight = height
|
||||||
|
}
|
||||||
|
|
||||||
override fun getViewStubId() = STUB_ID
|
override fun getViewStubId() = STUB_ID
|
||||||
|
|
||||||
class Holder : AbsMessageItem.Holder(STUB_ID) {
|
class Holder : AbsMessageItem.Holder(STUB_ID) {
|
||||||
|
@ -205,6 +225,7 @@ abstract class MessageAudioItem : AbsMessageItem<MessageAudioItem.Holder>() {
|
||||||
val audioPlaybackTime by bind<TextView>(R.id.audioPlaybackTime)
|
val audioPlaybackTime by bind<TextView>(R.id.audioPlaybackTime)
|
||||||
val progressLayout by bind<ViewGroup>(R.id.messageFileUploadProgressLayout)
|
val progressLayout by bind<ViewGroup>(R.id.messageFileUploadProgressLayout)
|
||||||
val fileSize by bind<TextView>(R.id.fileSize)
|
val fileSize by bind<TextView>(R.id.fileSize)
|
||||||
|
val captionView by bind<FooteredTextView>(R.id.messageCaptionView)
|
||||||
val audioPlaybackDuration by bind<TextView>(R.id.audioPlaybackDuration)
|
val audioPlaybackDuration by bind<TextView>(R.id.audioPlaybackDuration)
|
||||||
val audioSeekBar by bind<SeekBar>(R.id.audioSeekBar)
|
val audioSeekBar by bind<SeekBar>(R.id.audioSeekBar)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,12 @@ import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import com.airbnb.epoxy.EpoxyModelClass
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.onClick
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
|
import im.vector.app.core.ui.views.FooteredTextView
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
|
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
||||||
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.view.ScMessageBubbleWrapView
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.features.themes.guessTextWidth
|
import im.vector.app.features.themes.guessTextWidth
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
@ -43,6 +46,9 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var filename: String = ""
|
var filename: String = ""
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var caption: String? = null
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
var mxcUrl: String = ""
|
var mxcUrl: String = ""
|
||||||
|
|
||||||
|
@ -74,6 +80,7 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.filenameView.text = filename
|
holder.filenameView.text = filename
|
||||||
|
holder.captionView.setTextOrHide(caption)
|
||||||
|
|
||||||
if (attributes.informationData.sendState.isSending()) {
|
if (attributes.informationData.sendState.isSending()) {
|
||||||
holder.fileImageView.setImageResource(iconRes)
|
holder.fileImageView.setImageResource(iconRes)
|
||||||
|
@ -124,6 +131,19 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
|
||||||
holder.mainLayout.setPadding(0, 0, 0, 0)
|
holder.mainLayout.setPadding(0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hasCaption() = !caption.isNullOrBlank()
|
||||||
|
|
||||||
|
override fun allowFooterOverlay(holder: Holder, bubbleWrapView: ScMessageBubbleWrapView): Boolean = hasCaption()
|
||||||
|
|
||||||
|
override fun needsFooterReservation(): Boolean {
|
||||||
|
return hasCaption()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reserveFooterSpace(holder: Holder, width: Int, height: Int) {
|
||||||
|
holder.captionView.footerWidth = width
|
||||||
|
holder.captionView.footerHeight = height
|
||||||
|
}
|
||||||
|
|
||||||
override fun getViewStubId() = STUB_ID
|
override fun getViewStubId() = STUB_ID
|
||||||
|
|
||||||
class Holder : AbsMessageItem.Holder(STUB_ID) {
|
class Holder : AbsMessageItem.Holder(STUB_ID) {
|
||||||
|
@ -134,6 +154,7 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
|
||||||
val fileImageWrapper by bind<ViewGroup>(R.id.messageFileImageView)
|
val fileImageWrapper by bind<ViewGroup>(R.id.messageFileImageView)
|
||||||
val fileDownloadProgress by bind<ProgressBar>(R.id.messageFileProgressbar)
|
val fileDownloadProgress by bind<ProgressBar>(R.id.messageFileProgressbar)
|
||||||
val filenameView by bind<TextView>(R.id.messageFilenameView)
|
val filenameView by bind<TextView>(R.id.messageFilenameView)
|
||||||
|
val captionView by bind<FooteredTextView>(R.id.messageCaptionView)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -31,8 +31,10 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.ClickListener
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
import im.vector.app.core.epoxy.onClick
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.files.LocalFilesHelper
|
import im.vector.app.core.files.LocalFilesHelper
|
||||||
import im.vector.app.core.glide.GlideApp
|
import im.vector.app.core.glide.GlideApp
|
||||||
|
import im.vector.app.core.ui.views.FooteredTextView
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
||||||
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
|
||||||
|
@ -130,6 +132,8 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
holder.mediaContentView.onClick(attributes.itemClickListener)
|
holder.mediaContentView.onClick(attributes.itemClickListener)
|
||||||
holder.mediaContentView.setOnLongClickListener(attributes.itemLongClickListener)
|
holder.mediaContentView.setOnLongClickListener(attributes.itemLongClickListener)
|
||||||
|
|
||||||
|
holder.captionView.setTextOrHide(mediaData.caption)
|
||||||
|
|
||||||
holder.playContentView.visibility = if (animate) {
|
holder.playContentView.visibility = if (animate) {
|
||||||
View.GONE
|
View.GONE
|
||||||
} else if (playable) {
|
} else if (playable) {
|
||||||
|
@ -139,6 +143,8 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hasCaption() = !mediaData.caption.isNullOrBlank()
|
||||||
|
|
||||||
override fun unbind(holder: Holder) {
|
override fun unbind(holder: Holder) {
|
||||||
GlideApp.with(holder.view.context.applicationContext).clear(holder.imageView)
|
GlideApp.with(holder.view.context.applicationContext).clear(holder.imageView)
|
||||||
imageContentRenderer.clear(holder.imageView)
|
imageContentRenderer.clear(holder.imageView)
|
||||||
|
@ -151,6 +157,9 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
override fun getViewStubId() = STUB_ID
|
override fun getViewStubId() = STUB_ID
|
||||||
|
|
||||||
private fun shouldAllowFooterOverlay(footerMeasures: Array<Int>, imageWidth: Int, imageHeight: Int): Boolean {
|
private fun shouldAllowFooterOverlay(footerMeasures: Array<Int>, imageWidth: Int, imageHeight: Int): Boolean {
|
||||||
|
if (hasCaption()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
val footerWidth = footerMeasures[0]
|
val footerWidth = footerMeasures[0]
|
||||||
val footerHeight = footerMeasures[1]
|
val footerHeight = footerMeasures[1]
|
||||||
// We need enough space in both directions to remain within the image bounds.
|
// We need enough space in both directions to remain within the image bounds.
|
||||||
|
@ -159,6 +168,9 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldShowFooterBellow(footerMeasures: Array<Int>, imageWidth: Int, imageHeight: Int): Boolean {
|
private fun shouldShowFooterBellow(footerMeasures: Array<Int>, imageWidth: Int, imageHeight: Int): Boolean {
|
||||||
|
if (hasCaption()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
// Only show footer bellow if the width is not the limiting factor (or it will get cut).
|
// Only show footer bellow if the width is not the limiting factor (or it will get cut).
|
||||||
// Otherwise, we can not be sure in this place that we'll have enough space on the side
|
// Otherwise, we can not be sure in this place that we'll have enough space on the side
|
||||||
// Also, prefer footer on the side if possible (i.e. enough height available)
|
// Also, prefer footer on the side if possible (i.e. enough height available)
|
||||||
|
@ -168,6 +180,9 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allowFooterOverlay(holder: Holder, bubbleWrapView: ScMessageBubbleWrapView): Boolean {
|
override fun allowFooterOverlay(holder: Holder, bubbleWrapView: ScMessageBubbleWrapView): Boolean {
|
||||||
|
if (hasCaption()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
val rememberedAllowFooterOverlay = forceAllowFooterOverlay
|
val rememberedAllowFooterOverlay = forceAllowFooterOverlay
|
||||||
if (rememberedAllowFooterOverlay != null) {
|
if (rememberedAllowFooterOverlay != null) {
|
||||||
lastAllowedFooterOverlay = rememberedAllowFooterOverlay
|
lastAllowedFooterOverlay = rememberedAllowFooterOverlay
|
||||||
|
@ -187,15 +202,30 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allowFooterBelow(holder: Holder): Boolean {
|
override fun allowFooterBelow(holder: Holder): Boolean {
|
||||||
|
if (hasCaption()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
val showBellow = showFooterBellow
|
val showBellow = showFooterBellow
|
||||||
lastShowFooterBellow = showBellow
|
lastShowFooterBellow = showBellow
|
||||||
return showBellow
|
return showBellow
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getScBubbleMargin(resources: Resources): Int {
|
override fun getScBubbleMargin(resources: Resources): Int {
|
||||||
|
if (hasCaption()) {
|
||||||
|
return super.getScBubbleMargin(resources)
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun needsFooterReservation(): Boolean {
|
||||||
|
return hasCaption()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reserveFooterSpace(holder: Holder, width: Int, height: Int) {
|
||||||
|
holder.captionView.footerWidth = width
|
||||||
|
holder.captionView.footerHeight = height
|
||||||
|
}
|
||||||
|
|
||||||
override fun applyScBubbleStyle(messageLayout: TimelineMessageLayout.ScBubble, holder: Holder) {
|
override fun applyScBubbleStyle(messageLayout: TimelineMessageLayout.ScBubble, holder: Holder) {
|
||||||
// Case: ImageContentRenderer.processSize only sees width=height=0 -> width of the ImageView not adapted to the actual content
|
// Case: ImageContentRenderer.processSize only sees width=height=0 -> width of the ImageView not adapted to the actual content
|
||||||
// -> Align image within ImageView to same side as message bubbles
|
// -> Align image within ImageView to same side as message bubbles
|
||||||
|
@ -208,7 +238,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
when {
|
when {
|
||||||
// Don't show it for non-bubble layouts, don't show for Stickers, ...
|
// Don't show it for non-bubble layouts, don't show for Stickers, ...
|
||||||
// Also only supported for default corner radius
|
// Also only supported for default corner radius
|
||||||
!(messageLayout.isRealBubble || messageLayout.isPseudoBubble) || mode != ImageContentRenderer.Mode.THUMBNAIL -> {
|
!(messageLayout.isRealBubble || messageLayout.isPseudoBubble) || hasCaption() || mode != ImageContentRenderer.Mode.THUMBNAIL -> {
|
||||||
holder.mediaContentView.background = null
|
holder.mediaContentView.background = null
|
||||||
}
|
}
|
||||||
attributes.informationData.sentByMe -> {
|
attributes.informationData.sentByMe -> {
|
||||||
|
@ -223,6 +253,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
||||||
class Holder : AbsMessageItem.Holder(STUB_ID) {
|
class Holder : AbsMessageItem.Holder(STUB_ID) {
|
||||||
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 captionView by bind<FooteredTextView>(R.id.messageCaptionView)
|
||||||
val playContentView by bind<ImageView>(R.id.messageMediaPlayView)
|
val playContentView by bind<ImageView>(R.id.messageMediaPlayView)
|
||||||
val mediaContentView by bind<ViewGroup>(R.id.messageContentMedia)
|
val mediaContentView by bind<ViewGroup>(R.id.messageContentMedia)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageNoticeContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageNoticeContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getCaption
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.isEdition
|
import org.matrix.android.sdk.api.session.room.timeline.isEdition
|
||||||
|
@ -209,6 +211,7 @@ class TimelineMessageLayoutFactory @Inject constructor(
|
||||||
private fun MessageContent?.isPseudoBubble(event: TimelineEvent): Boolean {
|
private fun MessageContent?.isPseudoBubble(event: TimelineEvent): Boolean {
|
||||||
if (this == null) return false
|
if (this == null) return false
|
||||||
if (event.root.isRedacted()) return false
|
if (event.root.isRedacted()) return false
|
||||||
|
if (this is MessageWithAttachmentContent && !getCaption().isNullOrBlank()) return false
|
||||||
return this.msgType in MSG_TYPES_WITH_PSEUDO_BUBBLE_LAYOUT
|
return this.msgType in MSG_TYPES_WITH_PSEUDO_BUBBLE_LAYOUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ import kotlin.math.min
|
||||||
interface AttachmentData : Parcelable {
|
interface AttachmentData : Parcelable {
|
||||||
val eventId: String
|
val eventId: String
|
||||||
val filename: String
|
val filename: String
|
||||||
|
val caption: String?
|
||||||
val mimeType: String?
|
val mimeType: String?
|
||||||
val url: String?
|
val url: String?
|
||||||
val elementToDecrypt: ElementToDecrypt?
|
val elementToDecrypt: ElementToDecrypt?
|
||||||
|
@ -73,6 +74,7 @@ class ImageContentRenderer @Inject constructor(
|
||||||
data class Data(
|
data class Data(
|
||||||
override val eventId: String,
|
override val eventId: String,
|
||||||
override val filename: String,
|
override val filename: String,
|
||||||
|
override val caption: String?,
|
||||||
override val mimeType: String?,
|
override val mimeType: String?,
|
||||||
override val url: String?,
|
override val url: String?,
|
||||||
override val elementToDecrypt: ElementToDecrypt?,
|
override val elementToDecrypt: ElementToDecrypt?,
|
||||||
|
|
|
@ -29,6 +29,8 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getCaption
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
|
@ -60,7 +62,8 @@ class RoomEventsAttachmentProvider(
|
||||||
if (content is MessageImageContent) {
|
if (content is MessageImageContent) {
|
||||||
val data = ImageContentRenderer.Data(
|
val data = ImageContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.getFileUrl(),
|
url = content.getFileUrl(),
|
||||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
@ -87,7 +90,8 @@ class RoomEventsAttachmentProvider(
|
||||||
} else if (content is MessageStickerContent) {
|
} else if (content is MessageStickerContent) {
|
||||||
val data = ImageContentRenderer.Data(
|
val data = ImageContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.getFileUrl(),
|
url = content.getFileUrl(),
|
||||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
@ -114,7 +118,8 @@ class RoomEventsAttachmentProvider(
|
||||||
} else if (content is MessageVideoContent) {
|
} else if (content is MessageVideoContent) {
|
||||||
val thumbnailData = ImageContentRenderer.Data(
|
val thumbnailData = ImageContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.videoInfo?.getThumbnailUrl(),
|
url = content.videoInfo?.getThumbnailUrl(),
|
||||||
elementToDecrypt = content.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = content.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
|
@ -126,7 +131,8 @@ class RoomEventsAttachmentProvider(
|
||||||
)
|
)
|
||||||
val data = VideoContentRenderer.Data(
|
val data = VideoContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.getFileUrl(),
|
url = content.getFileUrl(),
|
||||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
|
|
@ -49,6 +49,7 @@ class VideoContentRenderer @Inject constructor(
|
||||||
data class Data(
|
data class Data(
|
||||||
override val eventId: String,
|
override val eventId: String,
|
||||||
override val filename: String,
|
override val filename: String,
|
||||||
|
override val caption: String?,
|
||||||
override val mimeType: String?,
|
override val mimeType: String?,
|
||||||
override val url: String?,
|
override val url: String?,
|
||||||
override val elementToDecrypt: ElementToDecrypt?,
|
override val elementToDecrypt: ElementToDecrypt?,
|
||||||
|
|
|
@ -50,6 +50,8 @@ import im.vector.app.features.roomprofile.uploads.RoomUploadsViewState
|
||||||
import org.matrix.android.sdk.api.session.crypto.attachments.toElementToDecrypt
|
import org.matrix.android.sdk.api.session.crypto.attachments.toElementToDecrypt
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getCaption
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -132,7 +134,8 @@ class RoomUploadsMediaFragment :
|
||||||
is MessageImageContent -> {
|
is MessageImageContent -> {
|
||||||
ImageContentRenderer.Data(
|
ImageContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.getFileUrl(),
|
url = content.getFileUrl(),
|
||||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
@ -145,7 +148,8 @@ class RoomUploadsMediaFragment :
|
||||||
is MessageVideoContent -> {
|
is MessageVideoContent -> {
|
||||||
val thumbnailData = ImageContentRenderer.Data(
|
val thumbnailData = ImageContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.videoInfo?.getThumbnailUrl(),
|
url = content.videoInfo?.getThumbnailUrl(),
|
||||||
elementToDecrypt = content.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = content.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
|
@ -156,7 +160,8 @@ class RoomUploadsMediaFragment :
|
||||||
)
|
)
|
||||||
VideoContentRenderer.Data(
|
VideoContentRenderer.Data(
|
||||||
eventId = it.eventId,
|
eventId = it.eventId,
|
||||||
filename = content.body,
|
filename = content.getFileName(),
|
||||||
|
caption = content.getCaption(),
|
||||||
mimeType = content.mimeType,
|
mimeType = content.mimeType,
|
||||||
url = content.getFileUrl(),
|
url = content.getFileUrl(),
|
||||||
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
|
|
@ -30,6 +30,8 @@ import org.matrix.android.sdk.api.session.crypto.attachments.toElementToDecrypt
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getCaption
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
import org.matrix.android.sdk.api.session.room.model.message.getThumbnailUrl
|
||||||
import org.matrix.android.sdk.api.session.room.uploads.UploadEvent
|
import org.matrix.android.sdk.api.session.room.uploads.UploadEvent
|
||||||
|
@ -108,7 +110,8 @@ class UploadsMediaController @Inject constructor(
|
||||||
|
|
||||||
return ImageContentRenderer.Data(
|
return ImageContentRenderer.Data(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
filename = messageContent.body,
|
filename = messageContent.getFileName(),
|
||||||
|
caption = messageContent.getCaption(),
|
||||||
url = messageContent.getFileUrl(),
|
url = messageContent.getFileUrl(),
|
||||||
mimeType = messageContent.mimeType,
|
mimeType = messageContent.mimeType,
|
||||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
@ -124,7 +127,8 @@ class UploadsMediaController @Inject constructor(
|
||||||
|
|
||||||
val thumbnailData = ImageContentRenderer.Data(
|
val thumbnailData = ImageContentRenderer.Data(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
filename = messageContent.body,
|
filename = messageContent.getFileName(),
|
||||||
|
caption = messageContent.getCaption(),
|
||||||
mimeType = messageContent.mimeType,
|
mimeType = messageContent.mimeType,
|
||||||
url = messageContent.videoInfo?.getThumbnailUrl(),
|
url = messageContent.videoInfo?.getThumbnailUrl(),
|
||||||
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.videoInfo?.thumbnailFile?.toElementToDecrypt(),
|
||||||
|
@ -136,7 +140,8 @@ class UploadsMediaController @Inject constructor(
|
||||||
|
|
||||||
return VideoContentRenderer.Data(
|
return VideoContentRenderer.Data(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
filename = messageContent.body,
|
filename = messageContent.getFileName(),
|
||||||
|
caption = messageContent.getCaption(),
|
||||||
mimeType = messageContent.mimeType,
|
mimeType = messageContent.mimeType,
|
||||||
url = messageContent.getFileUrl(),
|
url = messageContent.getFileUrl(),
|
||||||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||||
|
|
|
@ -95,6 +95,17 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.FooteredTextView
|
||||||
|
android:id="@+id/messageCaptionView"
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:layout_gravity="left"
|
||||||
|
tools:text="@sample/messages.json/data/message"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/messageFileUploadProgressLayout"
|
android:id="@+id/messageFileUploadProgressLayout"
|
||||||
layout="@layout/media_upload_download_progress_layout"
|
layout="@layout/media_upload_download_progress_layout"
|
||||||
|
|
|
@ -48,6 +48,17 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.FooteredTextView
|
||||||
|
android:id="@+id/messageCaptionView"
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:layout_gravity="left"
|
||||||
|
tools:text="@sample/messages.json/data/message"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/messageFileUploadProgressLayout"
|
android:id="@+id/messageFileUploadProgressLayout"
|
||||||
layout="@layout/media_upload_download_progress_layout"
|
layout="@layout/media_upload_download_progress_layout"
|
||||||
|
|
|
@ -18,6 +18,21 @@
|
||||||
tools:layout_height="300dp"
|
tools:layout_height="300dp"
|
||||||
tools:src="@tools:sample/backgrounds/scenic" />
|
tools:src="@tools:sample/backgrounds/scenic" />
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.FooteredTextView
|
||||||
|
android:id="@+id/messageCaptionView"
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:layout_gravity="left"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/messageThumbnailView"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
tools:text="@sample/messages.json/data/message"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/messageMediaPlayView"
|
android:id="@+id/messageMediaPlayView"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
|
@ -42,6 +57,6 @@
|
||||||
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/messageThumbnailView"
|
app:layout_constraintTop_toBottomOf="@id/messageTextView"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
Loading…
Reference in a new issue