Add media file limit size warning and media quality selection (#5131)
* Add `VideoCompressorPreset` enum This represents the different compression presets used for processing videos before uploading them * Add `VideoCompressorHelper` util class to calculate the scaled output size of the video given an input size and its optimal bitrate Also add `MediaOptimizationConfig` which will be used to decide how to apply compression in `MediaPreProcessor` * Add `RustMatrixClient.getMaxFileUploadSize()` function and `MaxUploadSizeProvider` so we can import only this functionality into other components * Try preloading the max file upload size the first time we get network connectivity - it's a best effort This should help ensure we'll have this value available later, even if we still need to load it asynchronously. * Split the `compressMedia` preference into `compressImages` and `compressMediaPreset` * Modify the media processing parts to use the new classes and utils * Add `MediaOptimizationSelectorPresenter`, which will retrieve the compression values and the max file upload size, also estimating the compressed video file sizes if needed. * Add a feature flag to allow selecting the media upload quality per upload * Integrate the previous changes with the attachments preview screen Add strings from localazy too. * Adapt the rest of the app calls to upload media to using the media optimization configs * Allow modifying the default compression values in advanced settings, based on the feature flag value * Pass the `fileSize` in `MediaUploadInfo` too, to be able to check it against the `maxUploadSize` * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
parent
ffe183c952
commit
a170d80cb3
174 changed files with 2152 additions and 340 deletions
|
|
@ -46,6 +46,7 @@ class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint
|
|||
eventId = null,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = filename,
|
||||
fileSize = null,
|
||||
caption = null,
|
||||
mimeType = mimeType,
|
||||
formattedFileSize = "",
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ class EventItemFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = type.filename,
|
||||
fileSize = type.info?.size,
|
||||
caption = type.caption,
|
||||
mimeType = type.info?.mimetype.orEmpty(),
|
||||
formattedFileSize = type.info?.size?.let { fileSizeFormatter.format(it) }.orEmpty(),
|
||||
|
|
@ -111,6 +112,7 @@ class EventItemFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = type.filename,
|
||||
fileSize = type.info?.size,
|
||||
caption = type.caption,
|
||||
mimeType = type.info?.mimetype.orEmpty(),
|
||||
formattedFileSize = type.info?.size?.let { fileSizeFormatter.format(it) }.orEmpty(),
|
||||
|
|
@ -131,6 +133,7 @@ class EventItemFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = type.filename,
|
||||
fileSize = type.info?.size,
|
||||
caption = type.caption,
|
||||
mimeType = type.info?.mimetype.orEmpty(),
|
||||
formattedFileSize = type.info?.size?.let { fileSizeFormatter.format(it) }.orEmpty(),
|
||||
|
|
@ -151,6 +154,7 @@ class EventItemFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = type.filename,
|
||||
fileSize = type.info?.size,
|
||||
caption = type.caption,
|
||||
mimeType = type.info?.mimetype.orEmpty(),
|
||||
formattedFileSize = type.info?.size?.let { fileSizeFormatter.format(it) }.orEmpty(),
|
||||
|
|
@ -171,6 +175,7 @@ class EventItemFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = type.filename,
|
||||
fileSize = type.info?.size,
|
||||
caption = type.caption,
|
||||
mimeType = type.info?.mimetype.orEmpty(),
|
||||
formattedFileSize = type.info?.size?.let { fileSizeFormatter.format(it) }.orEmpty(),
|
||||
|
|
@ -191,6 +196,7 @@ class EventItemFactory @Inject constructor(
|
|||
eventId = currentTimelineItem.eventId,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = type.filename,
|
||||
fileSize = type.info?.size,
|
||||
caption = type.caption,
|
||||
mimeType = type.info?.mimetype.orEmpty(),
|
||||
formattedFileSize = type.info?.size?.let { fileSizeFormatter.format(it) }.orEmpty(),
|
||||
|
|
|
|||
|
|
@ -87,15 +87,17 @@ class AndroidLocalMediaFactory @Inject constructor(
|
|||
): LocalMedia {
|
||||
val resolvedMimeType = mimeType ?: context.getMimeType(uri) ?: MimeTypes.OctetStream
|
||||
val fileName = name ?: context.getFileName(uri) ?: ""
|
||||
val fileSize = formattedFileSize ?: fileSizeFormatter.format(context.getFileSize(uri))
|
||||
val fileSize = context.getFileSize(uri)
|
||||
val calculatedFormattedFileSize = formattedFileSize ?: fileSizeFormatter.format(fileSize)
|
||||
val fileExtension = fileExtensionExtractor.extractFromName(fileName)
|
||||
return LocalMedia(
|
||||
uri = uri,
|
||||
info = MediaInfo(
|
||||
mimeType = resolvedMimeType,
|
||||
filename = fileName,
|
||||
fileSize = fileSize,
|
||||
caption = caption,
|
||||
formattedFileSize = fileSize,
|
||||
formattedFileSize = calculatedFormattedFileSize,
|
||||
fileExtension = fileExtension,
|
||||
senderId = senderId,
|
||||
senderName = senderName,
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ class DefaultEventItemFactoryTest {
|
|||
mediaInfo = MediaInfo(
|
||||
mimeType = MimeTypes.Apk,
|
||||
filename = "filename.apk",
|
||||
fileSize = 123L,
|
||||
caption = "caption",
|
||||
formattedFileSize = "123 Bytes",
|
||||
fileExtension = "apk",
|
||||
|
|
@ -205,6 +206,7 @@ class DefaultEventItemFactoryTest {
|
|||
mediaInfo = MediaInfo(
|
||||
mimeType = MimeTypes.Jpeg,
|
||||
filename = "filename.jpg",
|
||||
fileSize = 123L,
|
||||
caption = "caption",
|
||||
formattedFileSize = "123 Bytes",
|
||||
fileExtension = "jpg",
|
||||
|
|
@ -252,6 +254,7 @@ class DefaultEventItemFactoryTest {
|
|||
mediaInfo = MediaInfo(
|
||||
mimeType = MimeTypes.Mp3,
|
||||
filename = "filename.mp3",
|
||||
fileSize = 123L,
|
||||
caption = "caption",
|
||||
formattedFileSize = "123 Bytes",
|
||||
fileExtension = "mp3",
|
||||
|
|
@ -303,6 +306,7 @@ class DefaultEventItemFactoryTest {
|
|||
mediaInfo = MediaInfo(
|
||||
mimeType = MimeTypes.Mp4,
|
||||
filename = "filename.mp4",
|
||||
fileSize = 123L,
|
||||
caption = "caption",
|
||||
formattedFileSize = "123 Bytes",
|
||||
fileExtension = "mp4",
|
||||
|
|
@ -354,6 +358,7 @@ class DefaultEventItemFactoryTest {
|
|||
mediaInfo = MediaInfo(
|
||||
mimeType = MimeTypes.Ogg,
|
||||
filename = "filename.ogg",
|
||||
fileSize = 123L,
|
||||
caption = "caption",
|
||||
formattedFileSize = "123 Bytes",
|
||||
fileExtension = "ogg",
|
||||
|
|
@ -404,6 +409,7 @@ class DefaultEventItemFactoryTest {
|
|||
mediaInfo = MediaInfo(
|
||||
mimeType = MimeTypes.Gif,
|
||||
filename = "filename.gif",
|
||||
fileSize = 123L,
|
||||
caption = "caption",
|
||||
formattedFileSize = "123 Bytes",
|
||||
fileExtension = "gif",
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
eventId = AN_EVENT_ID,
|
||||
mediaInfo = MediaInfo(
|
||||
filename = "body.jpg",
|
||||
fileSize = 888L,
|
||||
caption = "body.jpg caption",
|
||||
mimeType = MimeTypes.Jpeg,
|
||||
formattedFileSize = "888 Bytes",
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class AndroidLocalMediaFactoryTest {
|
|||
assertThat(result.info).isEqualTo(
|
||||
MediaInfo(
|
||||
filename = "an image file.jpg",
|
||||
// MediaFile does not provide file size in this test
|
||||
fileSize = 0L,
|
||||
caption = null,
|
||||
mimeType = MimeTypes.Jpeg,
|
||||
formattedFileSize = "4MB",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue