From 16bf6bfc2c1a51d90c918773a96c72753e5f6fd3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 9 Nov 2023 13:32:06 +0100 Subject: [PATCH] Finished sending files through chat --- .../chat/fragment/ConversationFragment.kt | 7 +- .../linphone/ui/main/chat/model/FileModel.kt | 9 +++ .../chat/viewmodel/ConversationViewModel.kt | 32 +++++++- .../org/linphone/utils/DataBindingUtils.kt | 3 +- .../main/java/org/linphone/utils/FileUtils.kt | 76 +++++++++++-------- .../layout/chat_conversation_send_area.xml | 2 +- 6 files changed, 89 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt index 4f0bba697..0a9bbcdd7 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt @@ -165,6 +165,7 @@ class ConversationFragment : GenericFragment() { } override fun goBack(): Boolean { + coreContext.notificationsManager.resetCurrentlyDisplayedChatRoomId() sharedViewModel.closeSlidingPaneEvent.value = Event(true) // If not done, when going back to ConversationsFragment this fragment will be created again return findNavController().popBackStack() @@ -227,10 +228,6 @@ class ConversationFragment : GenericFragment() { startPostponedEnterTransition() sharedViewModel.openSlidingPaneEvent.value = Event(true) } - - if (currentCount < items.size) { - binding.eventsList.scrollToPosition(items.size - 1) - } } bottomSheetAdapter = ChatMessageBottomSheetAdapter(viewLifecycleOwner) @@ -412,6 +409,8 @@ class ConversationFragment : GenericFragment() { if (viewModel.scrollingPosition != SCROLLING_POSITION_NOT_SET) { binding.eventsList.scrollToPosition(viewModel.scrollingPosition) + } else { + binding.eventsList.scrollToPosition(adapter.itemCount - 1) } try { diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/FileModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/FileModel.kt index b5de388cb..c6ba76f64 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/FileModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/FileModel.kt @@ -1,5 +1,6 @@ package org.linphone.ui.main.chat.model +import android.webkit.MimeTypeMap import androidx.annotation.AnyThread import androidx.annotation.UiThread import androidx.lifecycle.MutableLiveData @@ -14,10 +15,18 @@ class FileModel @AnyThread constructor( private const val TAG = "[File Model]" } + val fileName: String = FileUtils.getNameFromFilePath(file) + val path = MutableLiveData() + val mimeType: FileUtils.MimeType + init { path.postValue(file) + + val extension = FileUtils.getExtensionFromFileName(file) + val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) + mimeType = FileUtils.getMimeType(mime) } @UiThread diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt index 62808ee4e..daec0be86 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt @@ -42,6 +42,7 @@ import org.linphone.ui.main.chat.model.ParticipantModel import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.utils.AppUtils import org.linphone.utils.Event +import org.linphone.utils.FileUtils import org.linphone.utils.LinphoneUtils class ConversationViewModel @UiThread constructor() : ViewModel() { @@ -364,6 +365,28 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { message.addUtf8TextContent(toSend) } + for (attachment in attachments.value.orEmpty()) { + val content = Factory.instance().createContent() + + content.type = when (attachment.mimeType) { + FileUtils.MimeType.Image -> "image" + FileUtils.MimeType.Audio -> "audio" + FileUtils.MimeType.Video -> "video" + FileUtils.MimeType.Pdf -> "application" + FileUtils.MimeType.PlainText -> "text" + else -> "file" + } + content.subtype = if (attachment.mimeType == FileUtils.MimeType.PlainText) { + "plain" + } else { + FileUtils.getExtensionFromFileName(attachment.fileName) + } + content.name = attachment.fileName + content.filePath = attachment.file // Let the file body handler take care of the upload + + message.addFileContent(content) + } + if (message.contents.isNotEmpty()) { Log.i("$TAG Sending message") message.send() @@ -372,6 +395,14 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { Log.i("$TAG Message sent, re-setting defaults") textToSend.postValue("") isReplying.postValue(false) + isFileAttachmentsListOpen.postValue(false) + isParticipantsListOpen.postValue(false) + isEmojiPickerOpen.postValue(false) + + // Warning: do not delete files + val attachmentsList = arrayListOf() + attachments.postValue(attachmentsList) + chatMessageToReplyTo = null } } @@ -545,7 +576,6 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { @WorkerThread private fun getEventsListFromHistory(history: Array, filter: String = ""): ArrayList { - var xFirstEventsSubmitted = false val eventsList = arrayListOf() val groupedEventLogs = arrayListOf() for (event in history) { diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index 8fa2b1e01..3bbc45d10 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -259,7 +259,8 @@ private fun loadImageForChatBubble(imageView: ImageView, file: String?, grid: Bo } } else { imageView.load(file) { - transformations(RoundedCornersTransformation(radius)) + // Can't have a transformation for gif file, breaks animation + // transformations(RoundedCornersTransformation(radius)) size(width, height) listener( onError = { _, result -> diff --git a/app/src/main/java/org/linphone/utils/FileUtils.kt b/app/src/main/java/org/linphone/utils/FileUtils.kt index f21debdc5..1c1f2059f 100644 --- a/app/src/main/java/org/linphone/utils/FileUtils.kt +++ b/app/src/main/java/org/linphone/utils/FileUtils.kt @@ -52,6 +52,49 @@ class FileUtils { companion object { private const val TAG = "[File Utils]" + @AnyThread + fun isExtensionVideo(path: String): Boolean { + val extension = getExtensionFromFileName(path) + val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) + return getMimeType(type) == MimeType.Video + } + + @AnyThread + fun getExtensionFromFileName(fileName: String): String { + var extension = MimeTypeMap.getFileExtensionFromUrl(fileName) + if (extension.isNullOrEmpty()) { + val i = fileName.lastIndexOf('.') + if (i > 0) { + extension = fileName.substring(i + 1) + } + } + + return extension.lowercase(Locale.getDefault()) + } + + @AnyThread + fun getMimeType(type: String?): MimeType { + if (type.isNullOrEmpty()) return MimeType.Unknown + return when { + type.startsWith("image/") -> MimeType.Image + type.startsWith("text/plain") -> MimeType.PlainText + type.startsWith("video/") -> MimeType.Video + type.startsWith("audio/") -> MimeType.Audio + type.startsWith("application/pdf") -> MimeType.Pdf + else -> MimeType.Unknown + } + } + + @AnyThread + fun getNameFromFilePath(filePath: String): String { + var name = filePath + val i = filePath.lastIndexOf('/') + if (i > 0) { + name = filePath.substring(i + 1) + } + return name + } + @AnyThread fun getProperFilePath(path: String): String { if (path.startsWith("file:") || path.startsWith("content:")) { @@ -271,38 +314,5 @@ class FileUtils { } return name } - - @AnyThread - fun isExtensionVideo(path: String): Boolean { - val extension = getExtensionFromFileName(path) - val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) - return getMimeType(type) == MimeType.Video - } - - @AnyThread - private fun getExtensionFromFileName(fileName: String): String { - var extension = MimeTypeMap.getFileExtensionFromUrl(fileName) - if (extension.isNullOrEmpty()) { - val i = fileName.lastIndexOf('.') - if (i > 0) { - extension = fileName.substring(i + 1) - } - } - - return extension.lowercase(Locale.getDefault()) - } - - @AnyThread - private fun getMimeType(type: String?): MimeType { - if (type.isNullOrEmpty()) return MimeType.Unknown - return when { - type.startsWith("image/") -> MimeType.Image - type.startsWith("text/plain") -> MimeType.PlainText - type.startsWith("video/") -> MimeType.Video - type.startsWith("audio/") -> MimeType.Audio - type.startsWith("application/pdf") -> MimeType.Pdf - else -> MimeType.Unknown - } - } } } diff --git a/app/src/main/res/layout/chat_conversation_send_area.xml b/app/src/main/res/layout/chat_conversation_send_area.xml index f20b79111..8d999a5ca 100644 --- a/app/src/main/res/layout/chat_conversation_send_area.xml +++ b/app/src/main/res/layout/chat_conversation_send_area.xml @@ -146,7 +146,7 @@ android:layout_width="40dp" android:layout_height="0dp" android:layout_marginEnd="4dp" - android:enabled="@{viewModel.textToSend.length() > 0}" + android:enabled="@{viewModel.textToSend.length() > 0 || viewModel.attachments.size() > 0}" android:onClick="@{() -> viewModel.sendMessage()}" android:padding="8dp" android:src="@drawable/paper_plane_tilt"