diff --git a/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt b/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt index d6e0f2de5..f41b3e13c 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt @@ -23,9 +23,11 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.view.LayoutInflater +import android.view.MenuInflater import android.view.MenuItem import android.view.ViewGroup -import androidx.appcompat.widget.PopupMenu +import androidx.appcompat.view.menu.MenuBuilder +import androidx.appcompat.view.menu.MenuPopupHelper import androidx.databinding.DataBindingUtil import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData @@ -134,7 +136,7 @@ class ChatMessagesListAdapter( inner class ChatMessageViewHolder( val binding: ChatMessageListCellBinding - ) : RecyclerView.ViewHolder(binding.root), PopupMenu.OnMenuItemClickListener { + ) : RecyclerView.ViewHolder(binding.root) { fun bind(eventLog: EventLog) { with(binding) { if (eventLog.type == EventLog.Type.ConferenceChatMessage) { @@ -192,61 +194,66 @@ class ChatMessagesListAdapter( if (contextMenuDisabled) return setContextMenuClickListener { - val popup = PopupMenu(root.context, background) - popup.setOnMenuItemClickListener(this@ChatMessageViewHolder) - popup.inflate(R.menu.chat_message_menu) + val builder = MenuBuilder(root.context) + val popupMenu = MenuPopupHelper(root.context, builder, background) + popupMenu.setForceShowIcon(true) + MenuInflater(root.context).inflate(R.menu.chat_message_menu, builder) if (chatMessage.chatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) || chatMessage.state == ChatMessage.State.NotDelivered) { // No message id - popup.menu.removeItem(R.id.chat_message_menu_imdn_infos) + builder.removeItem(R.id.chat_message_menu_imdn_infos) } if (chatMessage.state != ChatMessage.State.NotDelivered) { - popup.menu.removeItem(R.id.chat_message_menu_resend) + builder.removeItem(R.id.chat_message_menu_resend) } if (chatMessage.contents.find { content -> content.isText } == null) { - popup.menu.removeItem(R.id.chat_message_menu_copy_text) + builder.removeItem(R.id.chat_message_menu_copy_text) } - if (chatMessageViewModel.contact.value != null) { - popup.menu.removeItem(R.id.chat_message_menu_add_to_contacts) + if (chatMessage.isOutgoing || chatMessageViewModel.contact.value != null) { + builder.removeItem(R.id.chat_message_menu_add_to_contacts) } - popup.show() + builder.setCallback(object : MenuBuilder.Callback { + override fun onMenuModeChange(menu: MenuBuilder) {} + + override fun onMenuItemSelected(menu: MenuBuilder, item: MenuItem): Boolean { + return when (item.itemId) { + R.id.chat_message_menu_imdn_infos -> { + showImdnDeliveryFragment() + true + } + R.id.chat_message_menu_resend -> { + resendMessage() + true + } + R.id.chat_message_menu_copy_text -> { + copyTextToClipboard() + true + } + R.id.chat_message_forward_message -> { + forwardMessage() + true + } + R.id.chat_message_menu_delete_message -> { + deleteMessage() + true + } + R.id.chat_message_menu_add_to_contacts -> { + addSenderToContacts() + true + } + else -> false + } + } + }) + + popupMenu.show() true } } } } - override fun onMenuItemClick(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.chat_message_menu_imdn_infos -> { - showImdnDeliveryFragment() - true - } - R.id.chat_message_menu_resend -> { - resendMessage() - true - } - R.id.chat_message_menu_copy_text -> { - copyTextToClipboard() - true - } - R.id.chat_message_forward_message -> { - forwardMessage() - true - } - R.id.chat_message_menu_delete_message -> { - deleteMessage() - true - } - R.id.chat_message_menu_add_to_contacts -> { - addSenderToContacts() - true - } - else -> false - } - } - private fun resendMessage() { val chatMessage = binding.data?.chatMessage if (chatMessage != null) { 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 22c6b8235..a761aeb16 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 @@ -32,6 +32,8 @@ class ChatMessageAttachmentData( val fileName: String = FileUtils.getNameFromFilePath(path) val isImage: Boolean = FileUtils.isExtensionImage(path) 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()) 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 eeac47d2c..08dccdd5c 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 @@ -22,6 +22,7 @@ package org.linphone.activities.main.chat.data import android.graphics.Bitmap import androidx.lifecycle.MutableLiveData import kotlinx.coroutines.* +import org.linphone.R import org.linphone.core.ChatMessage import org.linphone.core.ChatMessageListenerStub import org.linphone.core.Content @@ -39,18 +40,17 @@ class ChatMessageContentData( val isVideo = MutableLiveData() val isAudio = MutableLiveData() val videoPreview = MutableLiveData() + val isPdf = MutableLiveData() + val isGenericFile = MutableLiveData() val fileName = MutableLiveData() - val filePath = MutableLiveData() - val fileSize = MutableLiveData() val downloadable = MutableLiveData() - val downloadEnabled = MutableLiveData() - val downloadProgress = MutableLiveData() + val downloadLabel = MutableLiveData() val isAlone: Boolean get() { @@ -97,6 +97,7 @@ class ChatMessageContentData( content.name } fileSize.value = AppUtils.bytesToDisplayableSize(content.fileSize.toLong()) + downloadLabel.value = "${AppUtils.getString(R.string.chat_message_download_file)} (${fileSize.value})" if (content.isFile || (content.isFileTransfer && chatMessage.isOutgoing)) { val path = if (content.isFileEncrypted) content.plainFilePath else content.filePath ?: "" @@ -108,6 +109,7 @@ class ChatMessageContentData( isImage.value = FileUtils.isExtensionImage(path) isVideo.value = FileUtils.isExtensionVideo(path) isAudio.value = FileUtils.isExtensionAudio(path) + isPdf.value = FileUtils.isExtensionPdf(path) if (isVideo.value == true) { scope.launch { @@ -121,14 +123,17 @@ class ChatMessageContentData( isImage.value = false isVideo.value = false isAudio.value = false + isPdf.value = false } } else { downloadable.value = true - isImage.value = false - isVideo.value = false - isAudio.value = false + isImage.value = FileUtils.isExtensionImage(fileName.value!!) + isVideo.value = FileUtils.isExtensionVideo(fileName.value!!) + isAudio.value = FileUtils.isExtensionAudio(fileName.value!!) + isPdf.value = FileUtils.isExtensionPdf(fileName.value!!) } + isGenericFile.value = !isPdf.value!! && !isAudio.value!! && !isVideo.value!! && !isImage.value!! downloadEnabled.value = !chatMessage.isFileTransferInProgress downloadProgress.value = 0 chatMessage.addListener(chatMessageListener) diff --git a/app/src/main/java/org/linphone/core/CorePreferences.kt b/app/src/main/java/org/linphone/core/CorePreferences.kt index ef63fdbb8..b2063b090 100644 --- a/app/src/main/java/org/linphone/core/CorePreferences.kt +++ b/app/src/main/java/org/linphone/core/CorePreferences.kt @@ -132,10 +132,8 @@ class CorePreferences constructor(private val context: Context) { /* Chat */ - // iOS and Android 4.4.x releases currently can't display more than 1 file per message - // TODO: Remove for the release, this won't be necessary anymore var preventMoreThanOneFilePerMessage: Boolean - get() = config.getBool("app", "prevent_more_than_one_file_per_message", true) + get() = config.getBool("app", "prevent_more_than_one_file_per_message", false) set(value) { config.setBool("app", "prevent_more_than_one_file_per_message", value) } diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index 972ff29d7..86bea09eb 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -92,6 +92,7 @@ fun ImageView.setImageMaxHeight(dimension: Float) { @BindingAdapter("android:layout_size") fun View.setLayoutSize(dimension: Float) { + if (dimension == 0f) return this.layoutParams.height = dimension.toInt() this.layoutParams.width = dimension.toInt() } @@ -304,6 +305,11 @@ fun setEntries( setEntries(viewGroup, entries, layoutId, null, parent) } +@BindingAdapter("android:scaleType") +fun setImageViewScaleType(imageView: ImageView, scaleType: ImageView.ScaleType) { + imageView.scaleType = scaleType +} + @BindingAdapter("glideAvatarFallback") fun loadAvatarWithGlideFallback(imageView: ImageView, path: String?) { if (path != null && path.isNotEmpty() && FileUtils.isExtensionImage(path)) { diff --git a/app/src/main/res/drawable-xhdpi/file.png b/app/src/main/res/drawable-xhdpi/file.png deleted file mode 100644 index 769cdc7ed..000000000 Binary files a/app/src/main/res/drawable-xhdpi/file.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/file_audio_default.png b/app/src/main/res/drawable-xhdpi/file_audio_default.png new file mode 100644 index 000000000..7cdd59372 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/file_audio_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/file_default.png b/app/src/main/res/drawable-xhdpi/file_default.png new file mode 100644 index 000000000..086edeacc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/file_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/file_pdf_default.png b/app/src/main/res/drawable-xhdpi/file_pdf_default.png new file mode 100644 index 000000000..eca17905f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/file_pdf_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/file_picture_default.png b/app/src/main/res/drawable-xhdpi/file_picture_default.png new file mode 100644 index 000000000..2bee7e7df Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/file_picture_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/file_video_default.png b/app/src/main/res/drawable-xhdpi/file_video_default.png new file mode 100644 index 000000000..f08f014f3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/file_video_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/menu_copy_text_default.png b/app/src/main/res/drawable-xhdpi/menu_copy_text_default.png new file mode 100644 index 000000000..ac945fb5e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/menu_copy_text_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/menu_forward_default.png b/app/src/main/res/drawable-xhdpi/menu_forward_default.png new file mode 100644 index 000000000..4212b9df2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/menu_forward_default.png differ diff --git a/app/src/main/res/drawable-xhdpi/menu_imdn_info_default.png b/app/src/main/res/drawable-xhdpi/menu_imdn_info_default.png new file mode 100644 index 000000000..1b83a3b9f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/menu_imdn_info_default.png differ diff --git a/app/src/main/res/drawable/file.xml b/app/src/main/res/drawable/file.xml new file mode 100644 index 000000000..662649d38 --- /dev/null +++ b/app/src/main/res/drawable/file.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/file_audio.xml b/app/src/main/res/drawable/file_audio.xml new file mode 100644 index 000000000..cd8223c10 --- /dev/null +++ b/app/src/main/res/drawable/file_audio.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/file_pdf.xml b/app/src/main/res/drawable/file_pdf.xml new file mode 100644 index 000000000..63c2db532 --- /dev/null +++ b/app/src/main/res/drawable/file_pdf.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/file_picture.xml b/app/src/main/res/drawable/file_picture.xml new file mode 100644 index 000000000..9fa961da4 --- /dev/null +++ b/app/src/main/res/drawable/file_picture.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/file_video.xml b/app/src/main/res/drawable/file_video.xml new file mode 100644 index 000000000..215d086a3 --- /dev/null +++ b/app/src/main/res/drawable/file_video.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/menu_copy_text.xml b/app/src/main/res/drawable/menu_copy_text.xml new file mode 100644 index 000000000..bf1f870e3 --- /dev/null +++ b/app/src/main/res/drawable/menu_copy_text.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/menu_delete.xml b/app/src/main/res/drawable/menu_delete.xml new file mode 100644 index 000000000..764e5bd35 --- /dev/null +++ b/app/src/main/res/drawable/menu_delete.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/menu_forward.xml b/app/src/main/res/drawable/menu_forward.xml new file mode 100644 index 000000000..b74011c5f --- /dev/null +++ b/app/src/main/res/drawable/menu_forward.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/menu_imdn_info.xml b/app/src/main/res/drawable/menu_imdn_info.xml new file mode 100644 index 000000000..4dbe5d99d --- /dev/null +++ b/app/src/main/res/drawable/menu_imdn_info.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + 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 328b66b36..e5c0d31de 100644 --- a/app/src/main/res/layout/chat_message_attachment_cell.xml +++ b/app/src/main/res/layout/chat_message_attachment_cell.xml @@ -10,37 +10,31 @@ - - - - - + android:background="?attr/backgroundColor" + android:visibility="@{data.image || data.video ? View.GONE : View.VISIBLE}"> + + + + diff --git a/app/src/main/res/layout/chat_message_content_cell.xml b/app/src/main/res/layout/chat_message_content_cell.xml index 124487d04..5c8c86d93 100644 --- a/app/src/main/res/layout/chat_message_content_cell.xml +++ b/app/src/main/res/layout/chat_message_content_cell.xml @@ -4,6 +4,7 @@ + @@ -14,7 +15,8 @@ + android:layout_height="wrap_content" + android:layout_margin="5dp"> - - - - + android:background="?attr/backgroundColor" + android:visibility="@{data.downloadable || data.pdf || data.audio || data.genericFile ? View.VISIBLE : View.GONE}"> - + + - - - - - - - - - - - - - - + android:text="@{data.downloadLabel}" + android:onClick="@{() -> data.download()}" + android:visibility="@{data.downloadable ? View.VISIBLE : View.GONE}"/> diff --git a/app/src/main/res/layout/chat_room_detail_fragment.xml b/app/src/main/res/layout/chat_room_detail_fragment.xml index d0350a52c..4e5e0c789 100644 --- a/app/src/main/res/layout/chat_room_detail_fragment.xml +++ b/app/src/main/res/layout/chat_room_detail_fragment.xml @@ -150,7 +150,7 @@ \ No newline at end of file diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml index a66cf73be..019ec8e24 100644 --- a/app/src/main/res/values/dimen.xml +++ b/app/src/main/res/values/dimen.xml @@ -7,6 +7,8 @@ 3dp 200dp 100dp + 150dp + 30dp 600dp 200dp 50dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 34f71a876..89f0bb18b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -225,7 +225,7 @@ diff --git a/build.gradle b/build.gradle index c9e31e4a2..4f1406228 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ buildscript { maven { url "https://www.jitpack.io" } // for com.github.chrisbanes:PhotoView } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + classpath 'com.android.tools.build:gradle:4.2.1' classpath 'com.google.gms:google-services:4.3.5' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jlleitschuh.gradle:ktlint-gradle:9.1.1"