diff --git a/app/build.gradle b/app/build.gradle index 55b2ccd8a..51d1287ee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -235,6 +235,7 @@ dependencies { implementation("io.coil-kt:coil:$coil_version") implementation("io.coil-kt:coil-gif:$coil_version") implementation("io.coil-kt:coil-svg:$coil_version") + implementation("io.coil-kt:coil-video:$coil_version") // https://github.com/Baseflow/PhotoView/blob/master/LICENSE Apache v2.0 implementation 'com.github.chrisbanes:PhotoView:2.3.0' diff --git a/app/src/main/java/org/linphone/LinphoneApplication.kt b/app/src/main/java/org/linphone/LinphoneApplication.kt index e9109f555..7cb207dc7 100644 --- a/app/src/main/java/org/linphone/LinphoneApplication.kt +++ b/app/src/main/java/org/linphone/LinphoneApplication.kt @@ -27,6 +27,7 @@ import coil.ImageLoaderFactory import coil.decode.GifDecoder import coil.decode.ImageDecoderDecoder import coil.decode.SvgDecoder +import coil.decode.VideoFrameDecoder import coil.disk.DiskCache import coil.memory.MemoryCache import org.linphone.core.* @@ -86,6 +87,7 @@ class LinphoneApplication : Application(), ImageLoaderFactory { override fun newImageLoader(): ImageLoader { return ImageLoader.Builder(this) .components { + add(VideoFrameDecoder.Factory()) add(SvgDecoder.Factory()) if (Version.sdkAboveOrEqual(Version.API28_PIE_90)) { add(ImageDecoderDecoder.Factory()) diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt index a761aeb16..0dd0211e4 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt @@ -19,11 +19,7 @@ */ package org.linphone.activities.main.chat.data -import android.graphics.Bitmap -import androidx.lifecycle.MutableLiveData -import kotlinx.coroutines.* import org.linphone.utils.FileUtils -import org.linphone.utils.ImageUtils class ChatMessageAttachmentData( val path: String, @@ -34,23 +30,6 @@ class ChatMessageAttachmentData( val isVideo: Boolean = FileUtils.isExtensionVideo(path) val isAudio: Boolean = FileUtils.isExtensionAudio(path) val isPdf: Boolean = FileUtils.isExtensionPdf(path) - val videoPreview = MutableLiveData() - - private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob()) - - init { - if (isVideo) { - scope.launch { - withContext(Dispatchers.IO) { - videoPreview.postValue(ImageUtils.getVideoPreview(path)) - } - } - } - } - - fun destroy() { - scope.cancel() - } fun delete() { deleteCallback(this) diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt index 27d086927..8111a4125 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt @@ -19,7 +19,6 @@ */ package org.linphone.activities.main.chat.data -import android.graphics.Bitmap import android.text.Spannable import android.text.SpannableString import android.text.Spanned @@ -43,7 +42,6 @@ import org.linphone.core.* import org.linphone.core.tools.Log import org.linphone.utils.AppUtils import org.linphone.utils.FileUtils -import org.linphone.utils.ImageUtils import org.linphone.utils.TimestampUtils class ChatMessageContentData( @@ -57,7 +55,6 @@ class ChatMessageContentData( val isImage = MutableLiveData() val isVideo = MutableLiveData() val isAudio = MutableLiveData() - val videoPreview = MutableLiveData() val isPdf = MutableLiveData() val isGenericFile = MutableLiveData() val isVoiceRecording = MutableLiveData() @@ -264,12 +261,6 @@ class ChatMessageContentData( } else if (isConferenceIcs) { parseConferenceInvite(content) } - - if (isVideo.value == true) { - scope.launch { - videoPreview.postValue(ImageUtils.getVideoPreview(path)) - } - } } else if (isConferenceIcs) { Log.i("[Content] Found content with icalendar file") parseConferenceInvite(content) diff --git a/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatMessageSendingViewModel.kt b/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatMessageSendingViewModel.kt index 6f8015e74..ac1383603 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatMessageSendingViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/viewmodels/ChatMessageSendingViewModel.kt @@ -140,7 +140,6 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel() } override fun onCleared() { - attachments.value.orEmpty().forEach(ChatMessageAttachmentData::destroy) pendingChatMessageToReplyTo.value?.destroy() if (recorder.state != RecorderState.Closed) { @@ -191,7 +190,6 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel() val list = arrayListOf() list.addAll(attachments.value.orEmpty()) list.remove(attachment) - attachment.destroy() attachments.value = list sendMessageEnabled.value = textToSend.value.orEmpty().isNotEmpty() || list.isNotEmpty() || isPendingVoiceRecord.value == true @@ -266,7 +264,6 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel() } cancelReply() - attachments.value.orEmpty().forEach(ChatMessageAttachmentData::destroy) attachments.value = arrayListOf() textToSend.value = "" diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index f99a5dd64..8e02435fa 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -40,6 +40,7 @@ import androidx.constraintlayout.widget.Guideline import androidx.databinding.* import coil.load import coil.request.CachePolicy +import coil.request.videoFrameMillis import coil.transform.CircleCropTransformation import com.google.android.material.switchmaterial.SwitchMaterial import org.linphone.BR @@ -356,6 +357,15 @@ fun loadAvatarWithGlide(imageView: ImageView, path: String?) { } } +@BindingAdapter("coilVideoPreview") +fun loadVideoPreview(imageView: ImageView, path: String?) { + if (path != null && path.isNotEmpty() && FileUtils.isExtensionVideo(path)) { + imageView.load(path) { + videoFrameMillis(0) + } + } +} + @BindingAdapter("showSecurityLevel") fun ContactAvatarView.setShowAvatarSecurityLevel(visible: Boolean) { this.binding.securityBadgeVisibility = visible diff --git a/app/src/main/java/org/linphone/utils/ImageUtils.kt b/app/src/main/java/org/linphone/utils/ImageUtils.kt index 69351ebe6..fba8586bc 100644 --- a/app/src/main/java/org/linphone/utils/ImageUtils.kt +++ b/app/src/main/java/org/linphone/utils/ImageUtils.kt @@ -21,9 +21,7 @@ package org.linphone.utils import android.content.Context import android.graphics.* -import android.media.ThumbnailUtils import android.net.Uri -import android.provider.MediaStore import org.linphone.compatibility.Compatibility import org.linphone.core.tools.Log @@ -63,10 +61,6 @@ class ImageUtils { return rotatedBitmap } - fun getVideoPreview(path: String): Bitmap? { - return ThumbnailUtils.createVideoThumbnail(path, MediaStore.Images.Thumbnails.MINI_KIND) - } - private fun getRoundBitmap(bitmap: Bitmap): Bitmap? { val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) diff --git a/app/src/main/res/layout/chat_message_attachment_cell.xml b/app/src/main/res/layout/chat_message_attachment_cell.xml index 46a1a90db..69101b9ca 100644 --- a/app/src/main/res/layout/chat_message_attachment_cell.xml +++ b/app/src/main/res/layout/chat_message_attachment_cell.xml @@ -35,7 +35,7 @@ android:layout_alignParentLeft="true" android:adjustViewBounds="true" android:scaleType="centerCrop" - android:src="@{data.videoPreview}"/> + app:coilVideoPreview="@{data.path}"/> diff --git a/app/src/main/res/layout/chat_message_reply_content_cell.xml b/app/src/main/res/layout/chat_message_reply_content_cell.xml index fbcdb9c62..c37efff49 100644 --- a/app/src/main/res/layout/chat_message_reply_content_cell.xml +++ b/app/src/main/res/layout/chat_message_reply_content_cell.xml @@ -32,7 +32,7 @@ android:layout_height="wrap_content" android:maxHeight="@dimen/chat_message_bubble_image_height_small" android:layout_size="@{data.alone ? 0f : @dimen/chat_message_small_bubble_file_size}" - android:src="@{data.videoPreview}" + app:coilVideoPreview="@{data.filePath}" android:visibility="@{data.video ? View.VISIBLE : View.GONE}" android:scaleType="@{ScaleType.CENTER_CROP}" android:adjustViewBounds="true" /> diff --git a/app/src/main/res/layout/chat_message_reply_preview_content_cell.xml b/app/src/main/res/layout/chat_message_reply_preview_content_cell.xml index c266d5005..d083d517a 100644 --- a/app/src/main/res/layout/chat_message_reply_preview_content_cell.xml +++ b/app/src/main/res/layout/chat_message_reply_preview_content_cell.xml @@ -29,7 +29,7 @@ android:layout_width="@dimen/chat_message_small_bubble_file_size" android:layout_height="@dimen/chat_message_small_bubble_file_size" android:layout_margin="5dp" - android:src="@{data.videoPreview}" + app:coilVideoPreview="@{data.filePath}" android:visibility="@{data.video ? View.VISIBLE : View.GONE}" android:scaleType="@{ScaleType.CENTER_CROP}" android:adjustViewBounds="true" />