Fix / Support open and view of sending attachment

This commit is contained in:
Valere 2020-09-03 09:31:53 +02:00
parent e02b9b7736
commit 8103081e0e
9 changed files with 91 additions and 37 deletions

View File

@ -34,7 +34,8 @@ interface VideoLoaderTarget {
fun onVideoFileLoading(uid: String)
fun onVideoFileLoadFailed(uid: String)
fun onVideoFileReady(uid: String, file: File)
fun onVideoURLReady(uid: String, file: File)
fun onVideoURLReady(uid: String, path: String)
}
internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val contextView: ImageView) : VideoLoaderTarget {
@ -66,11 +67,21 @@ internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val
holder.videoFileLoadError()
}
override fun onVideoFileReady(uid: String, file: File) {
override fun onVideoURLReady(uid: String, file: File) {
if (holder.boundResourceUid != uid) return
arrangeForVideoReady()
holder.videoReady(file)
}
override fun onVideoURLReady(uid: String, contentPath: String) {
if (holder.boundResourceUid != uid) return
arrangeForVideoReady()
holder.videoReady(contentPath)
}
private fun arrangeForVideoReady() {
holder.thumbnailImage.isVisible = false
holder.loaderProgressBar.isVisible = false
holder.videoView.isVisible = true
holder.videoReady(file)
}
}

View File

@ -65,6 +65,13 @@ class VideoViewHolder constructor(itemView: View) :
}
}
fun videoReady(path: String) {
mVideoPath = path
if (isSelected) {
startPlaying()
}
}
fun videoFileLoadError() {
}

View File

@ -40,7 +40,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
data class UpdateQuickReactAction(val targetEventId: String, val selectedReaction: String, val add: Boolean) : RoomDetailAction()
data class NavigateToEvent(val eventId: String, val highlight: Boolean) : RoomDetailAction()
object MarkAllAsRead : RoomDetailAction()
data class DownloadOrOpen(val eventId: String, val messageFileContent: MessageWithAttachmentContent) : RoomDetailAction()
data class DownloadOrOpen(val eventId: String, val senderId: String?, val messageFileContent: MessageWithAttachmentContent) : RoomDetailAction()
data class HandleTombstoneEvent(val event: Event) : RoomDetailAction()
object AcceptInvite : RoomDetailAction()
object RejectInvite : RoomDetailAction()

View File

@ -1423,7 +1423,7 @@ class RoomDetailFragment @Inject constructor(
roomDetailViewModel.handle(RoomDetailAction.ResumeVerification(informationData.eventId, null))
}
is MessageWithAttachmentContent -> {
val action = RoomDetailAction.DownloadOrOpen(informationData.eventId, messageContent)
val action = RoomDetailAction.DownloadOrOpen(informationData.eventId, informationData.senderId, messageContent)
roomDetailViewModel.handle(action)
}
is EncryptedEventContent -> {

View File

@ -57,6 +57,7 @@ import org.commonmark.renderer.html.HtmlRenderer
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.extensions.tryThis
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
@ -990,8 +991,18 @@ class RoomDetailViewModel @AssistedInject constructor(
private fun handleOpenOrDownloadFile(action: RoomDetailAction.DownloadOrOpen) {
val mxcUrl = action.messageFileContent.getFileUrl()
val isLocalSendingFile = action.senderId == session.myUserId
&& action.messageFileContent.getFileUrl()?.startsWith("content://") ?: false
val isDownloaded = mxcUrl?.let { session.fileService().isFileInCache(it, action.messageFileContent.mimeType) } ?: false
if (isDownloaded) {
if (isLocalSendingFile) {
tryThis { Uri.parse(mxcUrl) }?.let {
_viewEvents.post(RoomDetailViewEvents.OpenFile(
action.messageFileContent.mimeType,
it,
null
))
}
} else if (isDownloaded) {
// we can open it
session.fileService().getTemporarySharableURI(mxcUrl!!, action.messageFileContent.mimeType)?.let { uri ->
_viewEvents.post(RoomDetailViewEvents.OpenFile(

View File

@ -27,6 +27,7 @@ import im.vector.lib.attachmentviewer.AttachmentSourceProvider
import im.vector.lib.attachmentviewer.ImageLoaderTarget
import im.vector.lib.attachmentviewer.VideoLoaderTarget
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.file.FileService
import java.io.File
@ -101,11 +102,7 @@ abstract class BaseAttachmentProvider(val imageContentRenderer: ImageContentRend
override fun loadVideo(target: VideoLoaderTarget, info: AttachmentInfo.Video) {
val data = info.data as? VideoContentRenderer.Data ?: return
// videoContentRenderer.render(data,
// holder.thumbnailImage,
// holder.loaderProgressBar,
// holder.videoView,
// holder.errorTextView)
imageContentRenderer.render(data.thumbnailMediaData, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
override fun onLoadFailed(errorDrawable: Drawable?) {
target.onThumbnailLoadFailed(info.uid, errorDrawable)
@ -120,24 +117,28 @@ abstract class BaseAttachmentProvider(val imageContentRenderer: ImageContentRend
}
})
target.onVideoFileLoading(info.uid)
fileService.downloadFile(
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
id = data.eventId,
mimeType = data.mimeType,
elementToDecrypt = data.elementToDecrypt,
fileName = data.filename,
url = data.url,
callback = object : MatrixCallback<File> {
override fun onSuccess(data: File) {
target.onVideoFileReady(info.uid, data)
}
if (data.url?.startsWith("content://").orFalse() && data.allowNonMxcUrls) {
target.onVideoURLReady(info.uid, data.url!!)
} else {
target.onVideoFileLoading(info.uid)
fileService.downloadFile(
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
id = data.eventId,
mimeType = data.mimeType,
elementToDecrypt = data.elementToDecrypt,
fileName = data.filename,
url = data.url,
callback = object : MatrixCallback<File> {
override fun onSuccess(data: File) {
target.onVideoURLReady(info.uid, data)
}
override fun onFailure(failure: Throwable) {
target.onVideoFileLoadFailed(info.uid)
override fun onFailure(failure: Throwable) {
target.onVideoFileLoadFailed(info.uid)
}
}
}
)
)
}
}
override fun clear(id: String) {

View File

@ -51,6 +51,8 @@ interface AttachmentData : Parcelable {
val mimeType: String?
val url: String?
val elementToDecrypt: ElementToDecrypt?
// If true will load non mxc url, be careful to set it only for images sent by you
val allowNonMxcUrls: Boolean
}
class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
@ -66,7 +68,9 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
val height: Int?,
val maxHeight: Int,
val width: Int?,
val maxWidth: Int
val maxWidth: Int,
// If true will load non mxc url, be careful to set it only for images sent by you
override val allowNonMxcUrls: Boolean = false
) : AttachmentData {
fun isLocalFile() = url.isLocalFile()
@ -121,7 +125,8 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
.load(data)
} else {
// Clear image
val resolvedUrl = activeSessionHolder.getActiveSession().contentUrlResolver().resolveFullSize(data.url)
val resolvedUrl = resolveUrl(data)
?: data.url.takeIf { data.allowNonMxcUrls }
GlideApp
.with(contextView)
.load(resolvedUrl)
@ -175,7 +180,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
.load(data)
} else {
// Clear image
val resolvedUrl = activeSessionHolder.getActiveSession().contentUrlResolver().resolveFullSize(data.url)
val resolvedUrl = resolveUrl(data)
GlideApp
.with(imageView)
.load(resolvedUrl)
@ -215,7 +220,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
val resolvedUrl = when (mode) {
Mode.FULL_SIZE,
Mode.STICKER -> contentUrlResolver.resolveFullSize(data.url)
Mode.STICKER -> resolveUrl(data)
Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, size.width, size.height, ContentUrlResolver.ThumbnailMethod.SCALE)
}
// Fallback to base url
@ -229,7 +234,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
error(
GlideApp
.with(imageView)
.load(contentUrlResolver.resolveFullSize(data.url))
.load(resolveUrl(data))
)
}
}
@ -242,7 +247,7 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
val (width, height) = processSize(data, Mode.THUMBNAIL)
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
val fullSize = contentUrlResolver.resolveFullSize(data.url)
val fullSize = resolveUrl(data)
val thumbnail = contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE)
if (fullSize.isNullOrBlank() || thumbnail.isNullOrBlank()) {
@ -262,6 +267,10 @@ class ImageContentRenderer @Inject constructor(private val activeSessionHolder:
)
}
private fun resolveUrl(data: Data) =
(activeSessionHolder.getActiveSession().contentUrlResolver().resolveFullSize(data.url)
?: data.url?.takeIf { data.isLocalFile() && data.allowNonMxcUrls })
private fun processSize(data: Data, mode: Mode): Size {
val maxImageWidth = data.maxWidth
val maxImageHeight = data.maxHeight

View File

@ -63,7 +63,9 @@ class RoomEventsAttachmentProvider(
maxHeight = -1,
maxWidth = -1,
width = null,
height = null
height = null,
allowNonMxcUrls = it.root.sendState.isSending()
)
if (content.mimeType == "image/gif") {
AttachmentInfo.AnimatedImage(
@ -89,7 +91,8 @@ class RoomEventsAttachmentProvider(
height = content.videoInfo?.height,
maxHeight = -1,
width = content.videoInfo?.width,
maxWidth = -1
maxWidth = -1,
allowNonMxcUrls = it.root.sendState.isSending()
)
val data = VideoContentRenderer.Data(
eventId = it.eventId,
@ -97,7 +100,8 @@ class RoomEventsAttachmentProvider(
mimeType = content.mimeType,
url = content.getFileUrl(),
elementToDecrypt = content.encryptedFileInfo?.toElementToDecrypt(),
thumbnailMediaData = thumbnailData
thumbnailMediaData = thumbnailData,
allowNonMxcUrls = it.root.sendState.isSending()
)
AttachmentInfo.Video(
uid = it.eventId,

View File

@ -24,12 +24,14 @@ import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.utils.isLocalFile
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.file.FileService
import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
import kotlinx.android.parcel.Parcelize
import timber.log.Timber
import java.io.File
import java.net.URLEncoder
import javax.inject.Inject
class VideoContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
@ -42,7 +44,9 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
override val mimeType: String?,
override val url: String?,
override val elementToDecrypt: ElementToDecrypt?,
val thumbnailMediaData: ImageContentRenderer.Data
val thumbnailMediaData: ImageContentRenderer.Data,
// If true will load non mxc url, be careful to set it only for video sent by you
override val allowNonMxcUrls: Boolean = false
) : AttachmentData
fun render(data: Data,
@ -60,6 +64,12 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
loadingView.isVisible = false
errorView.isVisible = true
errorView.setText(R.string.unknown_error)
} else if (data.url.isLocalFile() && data.allowNonMxcUrls) {
thumbnailView.isVisible = false
loadingView.isVisible = false
videoView.isVisible = true
videoView.setVideoPath(URLEncoder.encode(data.url, Charsets.US_ASCII.displayName()))
videoView.start()
} else {
thumbnailView.isVisible = true
loadingView.isVisible = true
@ -91,6 +101,7 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder:
}
} else {
val resolvedUrl = contentUrlResolver.resolveFullSize(data.url)
?: data.url?.takeIf { data.url.isLocalFile() && data.allowNonMxcUrls }
if (resolvedUrl == null) {
thumbnailView.isVisible = false