User can now select video when selecting Gallery to send attachments to a room

This commit is contained in:
Benoit Marty 2021-05-03 13:47:42 +02:00 committed by Benoit Marty
parent 570cffd3ed
commit 30a54cfdbc
9 changed files with 174 additions and 15 deletions

View file

@ -9,6 +9,7 @@ Improvements 🙌:
- Delete and react to stickers (#3250)
- Compress video before sending (#442)
- Improve file too big error detection (#3245)
- User can now select video when selecting Gallery to send attachments to a room
Bugfix 🐛:
- Message states cosmetic changes (#3007)

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2020 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.lib.multipicker
import android.content.Context
import android.content.Intent
import android.media.MediaMetadataRetriever
import android.provider.MediaStore
import im.vector.lib.multipicker.entity.MultiPickerBaseMediaType
import im.vector.lib.multipicker.entity.MultiPickerImageType
import im.vector.lib.multipicker.entity.MultiPickerVideoType
import im.vector.lib.multipicker.utils.ImageUtils
/**
* Image/Video Picker implementation
*/
class MediaPicker : Picker<MultiPickerBaseMediaType>() {
/**
* Call this function from onActivityResult(int, int, Intent).
* Returns selected image/video files or empty list if user did not select any files.
*/
override fun getSelectedFiles(context: Context, data: Intent?): List<MultiPickerBaseMediaType> {
val mediaList = mutableListOf<MultiPickerBaseMediaType>()
getSelectedUriList(data).forEach { selectedUri ->
val projection = arrayOf(
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.MIME_TYPE
)
context.contentResolver.query(
selectedUri,
projection,
null,
null,
null
)?.use { cursor ->
val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
val mimeTypeColumn = cursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE)
if (cursor.moveToNext()) {
val name = cursor.getString(nameColumn)
val size = cursor.getLong(sizeColumn)
val mimeType = cursor.getString(mimeTypeColumn)
if (mimeType.isMimeTypeVideo()) {
var duration = 0L
var width = 0
var height = 0
var orientation = 0
context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd ->
val mediaMetadataRetriever = MediaMetadataRetriever()
mediaMetadataRetriever.setDataSource(pfd.fileDescriptor)
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: 0
height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: 0
orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toInt() ?: 0
}
mediaList.add(
MultiPickerVideoType(
name,
size,
context.contentResolver.getType(selectedUri),
selectedUri,
width,
height,
orientation,
duration
)
)
} else {
// Assume it's an image
val bitmap = ImageUtils.getBitmap(context, selectedUri)
val orientation = ImageUtils.getOrientation(context, selectedUri)
mediaList.add(
MultiPickerImageType(
name,
size,
context.contentResolver.getType(selectedUri),
selectedUri,
bitmap?.width ?: 0,
bitmap?.height ?: 0,
orientation
)
)
}
}
}
}
return mediaList
}
override fun createIntent(): Intent {
return Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, !single)
type = "video/*, image/*"
val mimeTypes = arrayOf("image/*", "video/*")
putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
}
}
private fun String?.isMimeTypeVideo() = this?.startsWith("video/") == true
}

View file

@ -20,6 +20,7 @@ class MultiPicker<T> {
companion object Type {
val IMAGE by lazy { MultiPicker<ImagePicker>() }
val MEDIA by lazy { MultiPicker<MediaPicker>() }
val FILE by lazy { MultiPicker<FilePicker>() }
val VIDEO by lazy { MultiPicker<VideoPicker>() }
val AUDIO by lazy { MultiPicker<AudioPicker>() }
@ -31,6 +32,7 @@ class MultiPicker<T> {
return when (type) {
IMAGE -> ImagePicker() as T
VIDEO -> VideoPicker() as T
MEDIA -> MediaPicker() as T
FILE -> FilePicker() as T
AUDIO -> AudioPicker() as T
CONTACT -> ContactPicker() as T

View file

@ -23,7 +23,7 @@ data class MultiPickerImageType(
override val size: Long,
override val mimeType: String?,
override val contentUri: Uri,
val width: Int,
val height: Int,
val orientation: Int
) : MultiPickerBaseType
override val width: Int,
override val height: Int,
override val orientation: Int
) : MultiPickerBaseMediaType

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 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.lib.multipicker.entity
interface MultiPickerBaseMediaType : MultiPickerBaseType {
val width: Int
val height: Int
val orientation: Int
}

View file

@ -23,8 +23,8 @@ data class MultiPickerVideoType(
override val size: Long,
override val mimeType: String?,
override val contentUri: Uri,
val width: Int,
val height: Int,
val orientation: Int,
override val width: Int,
override val height: Int,
override val orientation: Int,
val duration: Long
) : MultiPickerBaseType
) : MultiPickerBaseMediaType

View file

@ -77,10 +77,10 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
}
/**
* Starts the process for handling image picking
* Starts the process for handling image/video picking
*/
fun selectGallery(activityResultLauncher: ActivityResultLauncher<Intent>) {
MultiPicker.get(MultiPicker.IMAGE).startWith(activityResultLauncher)
MultiPicker.get(MultiPicker.MEDIA).startWith(activityResultLauncher)
}
/**
@ -133,9 +133,9 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
}
}
fun onImageResult(data: Intent?) {
fun onMediaResult(data: Intent?) {
callback.onContentAttachmentsReady(
MultiPicker.get(MultiPicker.IMAGE)
MultiPicker.get(MultiPicker.MEDIA)
.getSelectedFiles(context, data)
.map { it.toContentAttachmentData() }
)

View file

@ -17,6 +17,7 @@
package im.vector.app.features.attachments
import im.vector.lib.multipicker.entity.MultiPickerAudioType
import im.vector.lib.multipicker.entity.MultiPickerBaseMediaType
import im.vector.lib.multipicker.entity.MultiPickerBaseType
import im.vector.lib.multipicker.entity.MultiPickerContactType
import im.vector.lib.multipicker.entity.MultiPickerFileType
@ -69,6 +70,14 @@ private fun MultiPickerBaseType.mapType(): ContentAttachmentData.Type {
}
}
fun MultiPickerBaseMediaType.toContentAttachmentData(): ContentAttachmentData {
return when (this) {
is MultiPickerImageType -> toContentAttachmentData()
is MultiPickerVideoType -> toContentAttachmentData()
else -> throw IllegalStateException("Unknown media type")
}
}
fun MultiPickerImageType.toContentAttachmentData(): ContentAttachmentData {
if (mimeType == null) Timber.w("No mimeType")
return ContentAttachmentData(

View file

@ -988,9 +988,9 @@ class RoomDetailFragment @Inject constructor(
}
}
private val attachmentImageActivityResultLauncher = registerStartForActivityResult {
private val attachmentMediaActivityResultLauncher = registerStartForActivityResult {
if (it.resultCode == Activity.RESULT_OK) {
attachmentsHelper.onImageResult(it.data)
attachmentsHelper.onMediaResult(it.data)
}
}
@ -1991,7 +1991,7 @@ class RoomDetailFragment @Inject constructor(
when (type) {
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(requireContext(), attachmentPhotoActivityResultLauncher)
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentImageActivityResultLauncher)
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher)
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher)
AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment)