mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Download file - WIP
This commit is contained in:
parent
12bd85e0a9
commit
a07f8b615e
14 changed files with 193 additions and 62 deletions
|
@ -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 {
|
||||
|
||||
|
|
|
@ -105,13 +105,6 @@ interface CryptoService {
|
|||
|
||||
fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>)
|
||||
|
||||
/**
|
||||
* 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<File>)
|
||||
|
||||
fun getEncryptionAlgorithm(roomId: String): String?
|
||||
|
||||
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
|
||||
|
|
|
@ -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<File>)
|
||||
}
|
|
@ -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<File>) {
|
||||
fileDecryptor.decryptFile(id, filename, url, elementToDecrypt, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt an event
|
||||
*
|
||||
|
|
|
@ -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<File>) {
|
||||
/**
|
||||
* 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<File>) {
|
||||
GlobalScope.launch(coroutineDispatchers.main) {
|
||||
withContext(coroutineDispatchers.io) {
|
||||
Try {
|
||||
// Create dir tree:
|
||||
// <cache>/DF/<md5(userId)>/<md5(id)>/
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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):
|
||||
// <cache>/MF/<md5(userId)>/<md5(id)>/
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<LiveEvent<String>>
|
||||
get() = _navigateToEvent
|
||||
|
||||
private val _downloadedFileEvent = MutableLiveData<LiveEvent<DownloadFileState>>()
|
||||
val downloadedFileEvent: LiveData<LiveEvent<DownloadFileState>>
|
||||
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<File> {
|
||||
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
|
||||
|
||||
|
|
|
@ -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?)
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ class MessageItemFactory @Inject constructor(
|
|||
}
|
||||
.clickListener(
|
||||
DebouncedClickListener(View.OnClickListener { _ ->
|
||||
callback?.onFileMessageClicked(messageContent)
|
||||
callback?.onFileMessageClicked(informationData.eventId, messageContent)
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -11,5 +11,8 @@
|
|||
<string name="send_file_step_encrypting_file">Encrypting file…</string>
|
||||
<string name="send_file_step_sending_file">Sending file (%1$s / %2$s)</string>
|
||||
|
||||
<string name="downloading_file">Downloading file %1$s…</string>
|
||||
<string name="downloaded_file">File %1$s has been downloaded!</string>
|
||||
|
||||
|
||||
</resources>
|
Loading…
Reference in a new issue