Fix / Support open and view of sending attachment
This commit is contained in:
parent
e02b9b7736
commit
8103081e0e
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,13 @@ class VideoViewHolder constructor(itemView: View) :
|
|||
}
|
||||
}
|
||||
|
||||
fun videoReady(path: String) {
|
||||
mVideoPath = path
|
||||
if (isSelected) {
|
||||
startPlaying()
|
||||
}
|
||||
}
|
||||
|
||||
fun videoFileLoadError() {
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 -> {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue