From a07f8b615e83e1d28238f56de64fa2893372d73c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 8 Jul 2019 19:06:17 +0200 Subject: [PATCH] Download file - WIP --- .../matrix/android/api/session/Session.kt | 2 + .../api/session/crypto/CryptoService.kt | 7 -- .../android/api/session/file/FileService.kt | 52 ++++++++++++++ .../android/internal/crypto/CryptoManager.kt | 6 -- .../DefaultFileService.kt} | 72 ++++++++++++------- .../internal/session/DefaultSession.kt | 24 ++++--- .../internal/session/room/RoomModule.kt | 4 ++ .../home/room/detail/RoomDetailActions.kt | 2 + .../home/room/detail/RoomDetailFragment.kt | 25 ++++--- .../home/room/detail/RoomDetailViewModel.kt | 49 +++++++++++++ .../timeline/TimelineEventController.kt | 2 +- .../timeline/factory/MessageItemFactory.kt | 2 +- .../features/media/VideoContentRenderer.kt | 5 +- vector/src/main/res/values/strings_riotX.xml | 3 + 14 files changed, 193 insertions(+), 62 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt rename matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/{crypto/FileDecryptor.kt => session/DefaultFileService.kt} (54%) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt index 864a9d6f..3621c6ad 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.cache.CacheService import im.vector.matrix.android.api.session.content.ContentUploadStateTracker import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.crypto.CryptoService +import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.api.session.group.GroupService import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.room.RoomDirectoryService @@ -46,6 +47,7 @@ interface Session : CacheService, SignOutService, FilterService, + FileService, PushRuleService, PushersService { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt index 06880ceb..8e933426 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/CryptoService.kt @@ -105,13 +105,6 @@ interface CryptoService { fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback) - /** - * Decrypt a file. - * Result will be a decrypted file, stored in the cache folder. id parameter will be used to create a sub folder to avoid name collision. - * You can pass the eventId - */ - fun decryptFile(id: String, filename: String, url: String, elementToDecrypt: ElementToDecrypt, callback: MatrixCallback) - fun getEncryptionAlgorithm(roomId: String): String? fun shouldEncryptForInvitedMembers(roomId: String): Boolean diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt new file mode 100644 index 00000000..296b7e15 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/file/FileService.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.api.session.file + +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt +import java.io.File + + +/** + * This interface defines methods to get files. + */ +interface FileService { + + enum class DownloadMode { + /** + * Download file in external storage + */ + TO_EXPORT, + /** + * Download file in cache + */ + FOR_INTERNAL_USE + } + + /** + * Download a file. + * Result will be a decrypted file, stored in the cache folder. id parameter will be used to create a sub folder to avoid name collision. + * You can pass the eventId + */ + fun downloadFile( + downloadMode: DownloadMode, + id: String, + fileName: String, + url: String?, + elementToDecrypt: ElementToDecrypt?, + callback: MatrixCallback) +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt index 99911749..342c7ee5 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoManager.kt @@ -114,8 +114,6 @@ internal class CryptoManager @Inject constructor( private val keysBackup: KeysBackup, // private val objectSigner: ObjectSigner, - // File decryptor - private val fileDecryptor: FileDecryptor, // private val oneTimeKeysUploader: OneTimeKeysUploader, // @@ -611,10 +609,6 @@ internal class CryptoManager @Inject constructor( } } - override fun decryptFile(id: String, filename: String, url: String, elementToDecrypt: ElementToDecrypt, callback: MatrixCallback) { - fileDecryptor.decryptFile(id, filename, url, elementToDecrypt, callback) - } - /** * Decrypt an event * diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/FileDecryptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt similarity index 54% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/FileDecryptor.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt index bcdd36f8..b23f56bc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/FileDecryptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultFileService.kt @@ -14,17 +14,18 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.crypto +package im.vector.matrix.android.internal.session import android.content.Context +import android.os.Environment import arrow.core.Try import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.content.ContentUrlResolver +import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments import im.vector.matrix.android.internal.extensions.foldToCallback -import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.md5 import im.vector.matrix.android.internal.util.writeToFile @@ -38,33 +39,29 @@ import java.io.File import java.io.IOException import javax.inject.Inject -@SessionScope -internal class FileDecryptor @Inject constructor(private val context: Context, - private val sessionParams: SessionParams, - private val contentUrlResolver: ContentUrlResolver, - private val coroutineDispatchers: MatrixCoroutineDispatchers) { +internal class DefaultFileService @Inject constructor(private val context: Context, + private val sessionParams: SessionParams, + private val contentUrlResolver: ContentUrlResolver, + private val coroutineDispatchers: MatrixCoroutineDispatchers) : FileService { val okHttpClient = OkHttpClient() - fun decryptFile(id: String, - fileName: String, - url: String, - elementToDecrypt: ElementToDecrypt, - callback: MatrixCallback) { + /** + * Download file in the cache folder, and eventually decrypt it + * TODO implement clear file, to delete "MF" + */ + override fun downloadFile(downloadMode: FileService.DownloadMode, + id: String, + fileName: String, + url: String?, + elementToDecrypt: ElementToDecrypt?, + callback: MatrixCallback) { GlobalScope.launch(coroutineDispatchers.main) { withContext(coroutineDispatchers.io) { Try { - // Create dir tree: - // /DF/// - val tmpFolderRoot = File(context.cacheDir, "DF") - val tmpFolderUser = File(tmpFolderRoot, sessionParams.credentials.userId.md5()) - val tmpFolder = File(tmpFolderUser, id.md5()) + val folder = getFolder(downloadMode, id) - if (!tmpFolder.exists()) { - tmpFolder.mkdirs() - } - - File(tmpFolder, fileName) + File(folder, fileName) }.map { destFile -> if (!destFile.exists()) { Try { @@ -79,11 +76,16 @@ internal class FileDecryptor @Inject constructor(private val context: Context, val response = okHttpClient.newCall(request).execute() val inputStream = response.body()?.byteStream() Timber.v("Response size ${response.body()?.contentLength()} - Stream available: ${inputStream?.available()}") - if (!response.isSuccessful) { + if (!response.isSuccessful + || inputStream == null) { throw IOException() } - MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt) ?: throw IllegalStateException("Decryption error") + if (elementToDecrypt != null) { + MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt) ?: throw IllegalStateException("Decryption error") + } else { + inputStream + } } .map { inputStream -> writeToFile(inputStream, destFile) @@ -96,4 +98,24 @@ internal class FileDecryptor @Inject constructor(private val context: Context, .foldToCallback(callback) } } -} \ No newline at end of file + + private fun getFolder(downloadMode: FileService.DownloadMode, id: String): File { + return when (downloadMode) { + FileService.DownloadMode.FOR_INTERNAL_USE -> { + // Create dir tree (MF stands for Matrix File): + // /MF/// + val tmpFolderRoot = File(context.cacheDir, "MF") + val tmpFolderUser = File(tmpFolderRoot, sessionParams.credentials.userId.md5()) + File(tmpFolderUser, id.md5()) + } + FileService.DownloadMode.TO_EXPORT -> { + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + } + } + .also { folder -> + if (!folder.exists()) { + folder.mkdirs() + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index 32311853..72fdadfc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -21,7 +21,6 @@ import android.os.Looper import androidx.annotation.MainThread import androidx.lifecycle.LiveData import androidx.work.WorkManager -import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.pushrules.PushRuleService @@ -30,6 +29,7 @@ import im.vector.matrix.android.api.session.cache.CacheService import im.vector.matrix.android.api.session.content.ContentUploadStateTracker import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.crypto.CryptoService +import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.api.session.group.GroupService import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.room.RoomDirectoryService @@ -61,20 +61,22 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se private val pushRuleService: PushRuleService, private val pushersService: PushersService, private val cryptoService: CryptoManager, + private val fileService: FileService, private val syncThread: SyncThread, private val contentUrlResolver: ContentUrlResolver, private val contentUploadProgressTracker: ContentUploadStateTracker) : Session, - RoomService by roomService, - RoomDirectoryService by roomDirectoryService, - GroupService by groupService, - UserService by userService, - CryptoService by cryptoService, - CacheService by cacheService, - SignOutService by signOutService, - FilterService by filterService, - PushRuleService by pushRuleService, - PushersService by pushersService { + RoomService by roomService, + RoomDirectoryService by roomDirectoryService, + GroupService by groupService, + UserService by userService, + CryptoService by cryptoService, + CacheService by cacheService, + SignOutService by signOutService, + FilterService by filterService, + FileService by fileService, + PushRuleService by pushRuleService, + PushersService by pushersService { private var isOpen = false diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index 9cf6ac69..09322e6a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.room import dagger.Binds import dagger.Module import dagger.Provides +import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.api.session.room.RoomDirectoryService import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.members.MembershipService @@ -27,6 +28,7 @@ import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.state.StateService import im.vector.matrix.android.api.session.room.timeline.TimelineService +import im.vector.matrix.android.internal.session.DefaultFileService import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.room.create.CreateRoomTask import im.vector.matrix.android.internal.session.room.create.DefaultCreateRoomTask @@ -138,4 +140,6 @@ internal abstract class RoomModule { @Binds abstract fun bindTimelineService(timelineService: DefaultTimelineService): TimelineService + @Binds + abstract fun bindFileService(fileService: DefaultFileService): FileService } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt index df5cfc96..d52b16ca 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt @@ -18,6 +18,7 @@ package im.vector.riotx.features.home.room.detail import com.jaiselrahman.filepicker.model.MediaFile import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary +import im.vector.matrix.android.api.session.room.model.message.MessageFileContent import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent @@ -33,6 +34,7 @@ sealed class RoomDetailActions { data class UpdateQuickReactAction(val targetEventId: String, val selectedReaction: String, val add: Boolean) : RoomDetailActions() data class ShowEditHistoryAction(val event: String, val editAggregatedSummary: EditAggregatedSummary) : RoomDetailActions() data class NavigateToEvent(val eventId: String, val position: Int?) : RoomDetailActions() + data class DownloadFile(val eventId: String, val messageFileContent: MessageFileContent) : RoomDetailActions() object AcceptInvite : RoomDetailActions() object RejectInvite : RoomDetailActions() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 72c17f63..ed137f24 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -63,19 +63,14 @@ import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.dialogs.DialogListItem import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer +import im.vector.riotx.core.error.ErrorFormatter import im.vector.riotx.core.extensions.hideKeyboard import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.extensions.setTextOrHide +import im.vector.riotx.core.files.addEntryToDownloadManager import im.vector.riotx.core.glide.GlideApp import im.vector.riotx.core.platform.VectorBaseFragment -import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO -import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA -import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA -import im.vector.riotx.core.utils.checkPermissions -import im.vector.riotx.core.utils.copyToClipboard -import im.vector.riotx.core.utils.openCamera -import im.vector.riotx.core.utils.shareMedia +import im.vector.riotx.core.utils.* import im.vector.riotx.features.autocomplete.command.AutocompleteCommandPresenter import im.vector.riotx.features.autocomplete.command.CommandAutocompletePolicy import im.vector.riotx.features.autocomplete.user.AutocompleteUserPresenter @@ -180,6 +175,7 @@ class RoomDetailFragment : @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var roomDetailViewModelFactory: RoomDetailViewModel.Factory @Inject lateinit var textComposerViewModelFactory: TextComposerViewModel.Factory + @Inject lateinit var errorFormatter: ErrorFormatter private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback @@ -220,6 +216,15 @@ class RoomDetailFragment : scrollOnHighlightedEventCallback.scheduleScrollTo(it) } + roomDetailViewModel.downloadedFileEvent.observeEvent(this) { downloadFileState -> + if (downloadFileState.throwable != null) { + requireActivity().toast(errorFormatter.toHumanReadable(downloadFileState.throwable)) + } else if (downloadFileState.file != null) { + requireActivity().toast(getString(R.string.downloaded_file, downloadFileState.file.path)) + addEntryToDownloadManager(requireContext(), downloadFileState.file, downloadFileState.mimeType) + } + } + roomDetailViewModel.selectSubscribe( RoomDetailViewState::sendMode, RoomDetailViewState::selectedEvent, @@ -615,8 +620,8 @@ class RoomDetailFragment : startActivity(intent) } - override fun onFileMessageClicked(messageFileContent: MessageFileContent) { - vectorBaseActivity.notImplemented("open file") + override fun onFileMessageClicked(eventId: String, messageFileContent: MessageFileContent) { + roomDetailViewModel.process(RoomDetailActions.DownloadFile(eventId, messageFileContent)) } override fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 83dcb415..0c1b4523 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -16,6 +16,7 @@ package im.vector.riotx.features.home.room.detail +import android.content.ClipDescription import android.net.Uri import android.text.TextUtils import androidx.lifecycle.LiveData @@ -31,10 +32,12 @@ import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.content.ContentAttachmentData import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt import im.vector.matrix.rx.rx import im.vector.riotx.R import im.vector.riotx.core.intent.getFilenameFromUri @@ -50,6 +53,7 @@ import io.reactivex.rxkotlin.subscribeBy import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer import timber.log.Timber +import java.io.File import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.TimeUnit @@ -113,6 +117,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro is RoomDetailActions.EnterEditMode -> handleEditAction(action) is RoomDetailActions.EnterQuoteMode -> handleQuoteAction(action) is RoomDetailActions.EnterReplyMode -> handleReplyAction(action) + is RoomDetailActions.DownloadFile -> handleDownloadFile(action) is RoomDetailActions.NavigateToEvent -> handleNavigateToEvent(action) else -> Timber.e("Unhandled Action: $action") } @@ -149,6 +154,10 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro val navigateToEvent: LiveData> get() = _navigateToEvent + private val _downloadedFileEvent = MutableLiveData>() + val downloadedFileEvent: LiveData> + get() = _downloadedFileEvent + // PRIVATE METHODS ***************************************************************************** @@ -433,6 +442,46 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } + data class DownloadFileState( + val mimeType: String, + val file: File?, + val throwable: Throwable? + ) + + private fun handleDownloadFile(action: RoomDetailActions.DownloadFile) { + session.downloadFile( + FileService.DownloadMode.TO_EXPORT, + action.eventId, + action.messageFileContent.filename ?: "file.dat", + action.messageFileContent.url, + action.messageFileContent.encryptedFileInfo?.toElementToDecrypt(), + object : MatrixCallback { + override fun onSuccess(data: File) { + _downloadedFileEvent.postValue(LiveEvent(DownloadFileState( + // Mimetype default to plain text, should not be used + action.messageFileContent.encryptedFileInfo?.mimetype + ?: action.messageFileContent.info?.mimeType + ?: ClipDescription.MIMETYPE_TEXT_PLAIN, + data, + null + ))) + } + + override fun onFailure(failure: Throwable) { + _downloadedFileEvent.postValue(LiveEvent(DownloadFileState( + // Mimetype default to plain text, should not be used + action.messageFileContent.encryptedFileInfo?.mimetype + ?: action.messageFileContent.info?.mimeType + ?: ClipDescription.MIMETYPE_TEXT_PLAIN, + null, + failure + ))) + } + }) + + } + + private fun handleNavigateToEvent(action: RoomDetailActions.NavigateToEvent) { val targetEventId = action.eventId diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt index ec1ea87e..0ecfa216 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt @@ -57,7 +57,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim fun onEncryptedMessageClicked(informationData: MessageInformationData, view: View) fun onImageMessageClicked(messageImageContent: MessageImageContent, mediaData: ImageContentRenderer.Data, view: View) fun onVideoMessageClicked(messageVideoContent: MessageVideoContent, mediaData: VideoContentRenderer.Data, view: View) - fun onFileMessageClicked(messageFileContent: MessageFileContent) + fun onFileMessageClicked(eventId: String, messageFileContent: MessageFileContent) fun onAudioMessageClicked(messageAudioContent: MessageAudioContent) fun onEditedDecorationClicked(informationData: MessageInformationData, editAggregatedSummary: EditAggregatedSummary?) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 17328ca0..d2289380 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -162,7 +162,7 @@ class MessageItemFactory @Inject constructor( } .clickListener( DebouncedClickListener(View.OnClickListener { _ -> - callback?.onFileMessageClicked(messageContent) + callback?.onFileMessageClicked(informationData.eventId, messageContent) })) } diff --git a/vector/src/main/java/im/vector/riotx/features/media/VideoContentRenderer.kt b/vector/src/main/java/im/vector/riotx/features/media/VideoContentRenderer.kt index c369f775..80114676 100644 --- a/vector/src/main/java/im/vector/riotx/features/media/VideoContentRenderer.kt +++ b/vector/src/main/java/im/vector/riotx/features/media/VideoContentRenderer.kt @@ -23,6 +23,7 @@ import android.widget.TextView import android.widget.VideoView import androidx.core.view.isVisible import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.file.FileService import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder @@ -64,7 +65,9 @@ class VideoContentRenderer @Inject constructor(private val activeSessionHolder: loadingView.isVisible = true activeSessionHolder.getActiveSession() - .decryptFile(data.eventId, + .downloadFile( + FileService.DownloadMode.FOR_INTERNAL_USE, + data.eventId, data.filename, data.url, data.elementToDecrypt, diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index 50b1cd83..8919438a 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -11,5 +11,8 @@ Encrypting file… Sending file (%1$s / %2$s) + Downloading file %1$s… + File %1$s has been downloaded! + \ No newline at end of file