Improved videos shared by chat preview

This commit is contained in:
Sylvain Berfini 2020-06-11 14:54:21 +02:00
parent f6a6459b29
commit 7ca36938df
9 changed files with 111 additions and 24 deletions

View file

@ -39,7 +39,6 @@ import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.tabs_fragment.*
import kotlinx.coroutines.launch
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
@ -518,8 +517,7 @@ class DetailChatRoomFragment : MasterFragment() {
private fun openFile(contentFilePath: String) {
val intent = Intent(Intent.ACTION_VIEW)
val path = contentFilePath
val contentUri: Uri = FileUtils.getPublicFilePath(requireContext(), path)
val contentUri: Uri = FileUtils.getPublicFilePath(requireContext(), contentFilePath)
val filePath: String = contentUri.toString()
Log.i("[Chat Message] Trying to open file: $filePath")
var type: String? = null
@ -535,7 +533,7 @@ class DetailChatRoomFragment : MasterFragment() {
if (type != null) {
Log.i("[Chat Message] Found matching MIME type $type")
} else {
type = FileUtils.getMimeFromFile(filePath)
type = "file/$extension"
Log.e("[Chat Message] Can't get MIME type from extension: $extension, will use $type")
}

View file

@ -19,15 +19,34 @@
*/
package org.linphone.activities.main.chat.viewmodels
import android.graphics.Bitmap
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.linphone.utils.FileUtils
import org.linphone.utils.ImageUtils
class ChatMessageAttachmentViewModel(
val path: String,
val isImage: Boolean,
private val deleteCallback: (attachment: ChatMessageAttachmentViewModel) -> Unit
) : ViewModel() {
val fileName: String = FileUtils.getNameFromFilePath(path)
val isImage: Boolean = FileUtils.isExtensionImage(path)
val isVideo: Boolean = FileUtils.isExtensionVideo(path)
val videoPreview = MutableLiveData<Bitmap>()
init {
if (isVideo) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
videoPreview.postValue(ImageUtils.getVideoPreview(path))
}
}
}
}
fun delete() {
deleteCallback(this)

View file

@ -19,12 +19,18 @@
*/
package org.linphone.activities.main.chat.viewmodels
import android.graphics.Bitmap
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.linphone.core.ChatMessage
import org.linphone.core.Content
import org.linphone.core.tools.Log
import org.linphone.utils.FileUtils
import org.linphone.utils.ImageUtils
class ChatMessageContentViewModel(
val content: Content,
@ -32,6 +38,8 @@ class ChatMessageContentViewModel(
private val listener: OnContentClickedListener?
) : ViewModel() {
val isImage = MutableLiveData<Boolean>()
val isVideo = MutableLiveData<Boolean>()
val videoPreview = MutableLiveData<Bitmap>()
val downloadable = MutableLiveData<Boolean>()
@ -55,14 +63,25 @@ class ChatMessageContentViewModel(
if (content.filePath.isNotEmpty()) {
Log.i("[Content] Found displayable content: ${content.filePath}")
isImage.value = FileUtils.isExtensionImage(content.filePath)
isVideo.value = FileUtils.isExtensionVideo(content.filePath)
if (isVideo.value == true) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
videoPreview.postValue(ImageUtils.getVideoPreview(content.filePath))
}
}
}
} else {
Log.w("[Content] Found content with empty path...")
isImage.value = false
isVideo.value = false
}
} else {
Log.i("[Content] Found downloadable content: ${content.name}")
downloadable.value = true
isImage.value = false
isVideo.value = false
}
downloadEnabled.value = downloadable.value

View file

@ -74,7 +74,7 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
fun addAttachment(path: String) {
val list = arrayListOf<ChatMessageAttachmentViewModel>()
list.addAll(attachments.value.orEmpty())
list.add(ChatMessageAttachmentViewModel(path, FileUtils.isExtensionImage(path)) {
list.add(ChatMessageAttachmentViewModel(path) {
removeAttachment(it)
})
attachments.value = list

View file

@ -20,6 +20,7 @@
package org.linphone.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.Editable
@ -54,6 +55,11 @@ fun ImageView.setSourceImageResource(resource: Int) {
this.setImageResource(resource)
}
@BindingAdapter("android:src")
fun ImageView.setSourceImageBitmap(bitmap: Bitmap?) {
if (bitmap != null) this.setImageBitmap(bitmap)
}
@BindingAdapter("android:contentDescription")
fun ImageView.setContentDescription(resource: Int) {
if (resource == 0) {

View file

@ -23,6 +23,7 @@ import android.content.Context
import android.net.Uri
import android.os.Environment
import android.provider.OpenableColumns
import android.webkit.MimeTypeMap
import androidx.core.content.FileProvider
import java.io.*
import java.text.SimpleDateFormat
@ -37,13 +38,6 @@ import org.linphone.core.tools.Log
class FileUtils {
companion object {
fun getMimeFromFile(path: String?): String? {
val filePath = path ?: ""
return if (isExtensionImage(filePath)) {
"image/" + getExtensionFromFileName(filePath)
} else "file/" + getExtensionFromFileName(filePath)
}
fun getNameFromFilePath(filePath: String): String {
var name = filePath
val i = filePath.lastIndexOf('/')
@ -54,17 +48,19 @@ class FileUtils {
}
fun getExtensionFromFileName(fileName: String): String {
var extension = ""
val i = fileName.lastIndexOf('.')
if (i > 0) {
extension = fileName.substring(i + 1)
}
return extension
return MimeTypeMap.getFileExtensionFromUrl(fileName)
}
fun isExtensionImage(path: String): Boolean {
val extension = getExtensionFromFileName(path).toLowerCase(Locale.getDefault())
return extension.matches(Regex("(png|jpg|jpeg|bmp|gif)"))
val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
return type?.startsWith("image/") ?: false
}
fun isExtensionVideo(path: String): Boolean {
val extension = getExtensionFromFileName(path).toLowerCase(Locale.getDefault())
val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
return type?.startsWith("video/") ?: false
}
fun getFileStorageDir(isPicture: Boolean = false): File {

View file

@ -21,6 +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
@ -62,6 +63,10 @@ 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)

View file

@ -34,9 +34,35 @@
android:layout_alignRight="@id/pendingImageForUpload"
android:src="@drawable/clean_field" />
<ImageView
android:id="@+id/pendingVideoForUpload"
android:visibility="@{data.video ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_pending_file_transfer"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:adjustViewBounds="true"
android:src="@{data.videoPreview}"/>
<ImageView
android:visibility="@{data.video ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/recording_play_pause"
android:layout_centerInParent="true"/>
<ImageView
android:visibility="@{data.video ? View.VISIBLE : View.GONE, default=gone}"
android:onClick="@{() -> data.delete()}"
android:contentDescription="@string/content_description_remove_pending_file_transfer"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignTop="@id/pendingVideoForUpload"
android:layout_alignRight="@id/pendingVideoForUpload"
android:src="@drawable/clean_field" />
<TextView
android:id="@+id/pendingFileForUpload"
android:visibility="@{data.image ? View.GONE : View.VISIBLE}"
android:visibility="@{data.image || data.video ? View.GONE : View.VISIBLE, default=gone}"
android:text="@{data.fileName}"
android:textColor="?attr/secondaryTextColor"
android:textSize="21sp"
@ -47,7 +73,7 @@
android:textAlignment="center" />
<ImageView
android:visibility="@{data.image ? View.GONE : View.VISIBLE}"
android:visibility="@{data.image || data.video ? View.GONE : View.VISIBLE, default=gone}"
android:onClick="@{() -> data.delete()}"
android:contentDescription="@string/content_description_remove_pending_file_transfer"
android:layout_width="20dp"

View file

@ -24,9 +24,27 @@
android:layout_height="@{data.alone ? @dimen/chat_message_bubble_image_height_big : @dimen/chat_message_bubble_image_height_small, default=wrap_content}"
android:layout_margin="5dp"
app:glidePath="@{data.content.filePath}"
android:visibility="@{data.isImage() ? View.VISIBLE : View.GONE}"
android:visibility="@{data.image ? View.VISIBLE : View.GONE}"
android:adjustViewBounds="true" />
<ImageView
android:onClick="@{() -> data.openFile()}"
android:onLongClick="@{longClickListener}"
android:contentDescription="@string/content_description_downloaded_file_transfer"
android:layout_width="wrap_content"
android:layout_height="@{data.alone ? @dimen/chat_message_bubble_image_height_big : @dimen/chat_message_bubble_image_height_small, default=wrap_content}"
android:layout_margin="5dp"
android:src="@{data.videoPreview}"
android:visibility="@{data.video ? View.VISIBLE : View.GONE, default=gone}"
android:adjustViewBounds="true" />
<ImageView
android:visibility="@{data.video ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/recording_play_pause"
android:layout_centerInParent="true"/>
<TextView
android:onClick="@{() -> data.openFile()}"
android:onLongClick="@{longClickListener}"
@ -35,7 +53,7 @@
android:fontFamily="sans-serif"
android:textStyle="normal"
android:text="@{data.content.name}"
android:visibility="@{data.downloadable || data.isImage() ? View.GONE : View.VISIBLE}"
android:visibility="@{data.downloadable || data.image || data.video ? View.GONE : View.VISIBLE, default=gone}"
android:layout_width="150dp"
android:layout_height="100dp"
android:layout_margin="5dp"