From ad1625dbb36ec7af02282eaff928276591835a26 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Nov 2023 16:30:33 +0100 Subject: [PATCH] Started image viewer --- .../chat/fragment/ConversationFragment.kt | 10 ++ .../ui/main/chat/model/ChatMessageModel.kt | 20 ++-- .../ui/main/chat/model/EventLogModel.kt | 12 +- .../linphone/ui/main/chat/model/FileModel.kt | 19 ++++ .../chat/viewmodel/ConversationViewModel.kt | 12 +- .../viewer/fragment/FileViewerFragment.kt | 58 ++++++++++ .../ui/main/viewer/viewmodel/FileViewModel.kt | 13 +++ .../org/linphone/utils/DataBindingUtils.kt | 8 ++ app/src/main/res/drawable/download_simple.xml | 9 ++ .../main/res/layout/chat_bubble_content.xml | 5 +- .../layout/chat_bubble_content_grid_cell.xml | 5 +- .../res/layout/file_image_viewer_fragment.xml | 107 ++++++++++++++++++ .../main/res/navigation/chat_nav_graph.xml | 17 +++ 13 files changed, 276 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/main/chat/model/FileModel.kt create mode 100644 app/src/main/java/org/linphone/ui/main/viewer/fragment/FileViewerFragment.kt create mode 100644 app/src/main/java/org/linphone/ui/main/viewer/viewmodel/FileViewModel.kt create mode 100644 app/src/main/res/drawable/download_simple.xml create mode 100644 app/src/main/res/layout/file_image_viewer_fragment.xml 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 7e567fca6..1573b5dbf 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 @@ -260,6 +260,16 @@ class ConversationFragment : GenericFragment() { } } + viewModel.fileToDisplayEvent.observe(viewLifecycleOwner) { + it.consume { file -> + Log.i("$TAG User clicked on file [$file], let's display it in file viewer") + val action = ConversationFragmentDirections.actionConversationFragmentToFileViewerFragment( + file + ) + findNavController().navigate(action) + } + } + binding.root.setKeyboardInsetListener { keyboardVisible -> if (keyboardVisible) { viewModel.isEmojiPickerOpen.value = false diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt index 9efde75c2..7619f43e2 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ChatMessageModel.kt @@ -48,7 +48,8 @@ class ChatMessageModel @WorkerThread constructor( val replyText: String, val replyToMessageId: String?, val isGroupedWithPreviousOne: Boolean, - val isGroupedWithNextOne: Boolean + val isGroupedWithNextOne: Boolean, + val onContentClicked: ((file: String) -> Unit)? = null ) { companion object { private const val TAG = "[Chat Message Model]" @@ -73,9 +74,9 @@ class ChatMessageModel @WorkerThread constructor( val reactions = MutableLiveData() - val imagesList = MutableLiveData>() + val imagesList = MutableLiveData>() - val firstImage = MutableLiveData() + val firstImage = MutableLiveData() val dismissLongPressMenuEvent: MutableLiveData> by lazy { MutableLiveData>() @@ -109,7 +110,7 @@ class ChatMessageModel @WorkerThread constructor( var displayableContentFound = false var filesContentCount = 0 - val imagesPath = arrayListOf() + val imagesPath = arrayListOf() val contents = chatMessage.contents for (content in contents) { @@ -126,10 +127,15 @@ class ChatMessageModel @WorkerThread constructor( ) when (content.type) { "image", "video" -> { - imagesPath.add(path) - if (filesContentCount == 1) { - firstImage.postValue(path) + val fileModel = FileModel(path) { file -> + onContentClicked?.invoke(file) } + imagesPath.add(fileModel) + + if (filesContentCount == 1) { + firstImage.postValue(fileModel) + } + displayableContentFound = true } "audio" -> { diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/EventLogModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/EventLogModel.kt index fe90a5e5e..d9bcba34a 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/EventLogModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/EventLogModel.kt @@ -30,7 +30,8 @@ class EventLogModel @WorkerThread constructor( avatarModel: ContactAvatarModel, isFromGroup: Boolean, isGroupedWithPreviousOne: Boolean, - isGroupedWithNextOne: Boolean + isGroupedWithNextOne: Boolean, + onContentClicked: ((file: String) -> Unit)? = null ) { companion object { private const val TAG = "[Event Log Model]" @@ -40,7 +41,7 @@ class EventLogModel @WorkerThread constructor( val isEvent = type != EventLog.Type.ConferenceChatMessage - val model = if (isEvent) { + val model: Any = if (isEvent) { EventModel(eventLog) } else { val chatMessage = eventLog.chatMessage!! @@ -66,7 +67,8 @@ class EventLogModel @WorkerThread constructor( reply, chatMessage.replyMessageId, isGroupedWithPreviousOne, - isGroupedWithNextOne + isGroupedWithNextOne, + onContentClicked ) } @@ -74,8 +76,6 @@ class EventLogModel @WorkerThread constructor( @WorkerThread fun destroy() { - if (model is ChatMessageModel) { - model.destroy() - } + (model as? ChatMessageModel)?.destroy() } } 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 new file mode 100644 index 000000000..275aa470c --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/chat/model/FileModel.kt @@ -0,0 +1,19 @@ +package org.linphone.ui.main.chat.model + +import androidx.annotation.WorkerThread +import androidx.lifecycle.MutableLiveData + +class FileModel @WorkerThread constructor( + val file: String, + private val onClicked: ((file: String) -> Unit)? = null +) { + val path = MutableLiveData() + + init { + path.postValue(file) + } + + fun onClick() { + onClicked?.invoke(file) + } +} 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 4695b7fc1..64f7fcd48 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 @@ -83,6 +83,10 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { MutableLiveData>() } + val fileToDisplayEvent: MutableLiveData> by lazy { + MutableLiveData>() + } + val chatRoomFoundEvent = MutableLiveData>() private lateinit var chatRoom: ChatRoom @@ -114,7 +118,9 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { LinphoneUtils.isChatRoomAGroup(chatRoom), group, true - ) + ) { file -> + fileToDisplayEvent.postValue(Event(file)) + } ) events.postValue(list) @@ -387,7 +393,9 @@ class ConversationViewModel @UiThread constructor() : ViewModel() { groupChatRoom, index > 0, index == groupedEventLogs.size - 1 - ) + ) { file -> + fileToDisplayEvent.postValue(Event(file)) + } eventsList.add(model) index += 1 diff --git a/app/src/main/java/org/linphone/ui/main/viewer/fragment/FileViewerFragment.kt b/app/src/main/java/org/linphone/ui/main/viewer/fragment/FileViewerFragment.kt new file mode 100644 index 000000000..443b2ef85 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/viewer/fragment/FileViewerFragment.kt @@ -0,0 +1,58 @@ +package org.linphone.ui.main.viewer.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.UiThread +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import org.linphone.core.tools.Log +import org.linphone.databinding.FileImageViewerFragmentBinding +import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.viewer.viewmodel.FileViewModel + +@UiThread +class FileViewerFragment : GenericFragment() { + companion object { + private const val TAG = "[File Viewer Fragment]" + } + + private lateinit var binding: FileImageViewerFragmentBinding + + private lateinit var viewModel: FileViewModel + + private val args: FileViewerFragmentArgs by navArgs() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FileImageViewerFragmentBinding.inflate(layoutInflater) + return binding.root + } + + override fun goBack(): Boolean { + return findNavController().popBackStack() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + isSlidingPaneChild = true + super.onViewCreated(view, savedInstanceState) + + viewModel = ViewModelProvider(this)[FileViewModel::class.java] + + binding.lifecycleOwner = viewLifecycleOwner + binding.viewModel = viewModel + + val path = args.path + Log.i("$TAG Path argument is [$path]") + viewModel.loadFile(path) + + binding.setBackClickListener { + goBack() + } + } +} diff --git a/app/src/main/java/org/linphone/ui/main/viewer/viewmodel/FileViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewer/viewmodel/FileViewModel.kt new file mode 100644 index 000000000..eb5c5cb08 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/viewer/viewmodel/FileViewModel.kt @@ -0,0 +1,13 @@ +package org.linphone.ui.main.viewer.viewmodel + +import androidx.annotation.UiThread +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class FileViewModel @UiThread constructor() : ViewModel() { + val path = MutableLiveData() + + fun loadFile(file: String) { + path.postValue(file) + } +} diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index e2fe5c416..d222c41b9 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -207,6 +207,14 @@ fun AppCompatTextView.setColor(@ColorRes color: Int) { setTextColor(AppUtils.getColor(color)) } +@UiThread +@BindingAdapter("coilFile") +fun ImageView.loadFileImage(file: String?) { + if (!file.isNullOrEmpty()) { + load(file) + } +} + @UiThread @BindingAdapter("coilBubble") fun ImageView.loadImageForChatBubble(file: String?) { diff --git a/app/src/main/res/drawable/download_simple.xml b/app/src/main/res/drawable/download_simple.xml new file mode 100644 index 000000000..129d4671c --- /dev/null +++ b/app/src/main/res/drawable/download_simple.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/chat_bubble_content.xml b/app/src/main/res/layout/chat_bubble_content.xml index 58c5d0f92..ca4e4ce02 100644 --- a/app/src/main/res/layout/chat_bubble_content.xml +++ b/app/src/main/res/layout/chat_bubble_content.xml @@ -31,16 +31,17 @@ + coilBubble="@{model.firstImage.path}"/> + type="org.linphone.ui.main.chat.model.FileModel" /> + coilBubble="@{model.path}"/> \ No newline at end of file diff --git a/app/src/main/res/layout/file_image_viewer_fragment.xml b/app/src/main/res/layout/file_image_viewer_fragment.xml new file mode 100644 index 000000000..8052e375d --- /dev/null +++ b/app/src/main/res/layout/file_image_viewer_fragment.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/chat_nav_graph.xml b/app/src/main/res/navigation/chat_nav_graph.xml index 286fda8b1..99d2bc0e4 100644 --- a/app/src/main/res/navigation/chat_nav_graph.xml +++ b/app/src/main/res/navigation/chat_nav_graph.xml @@ -29,6 +29,13 @@ app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> + + + + + \ No newline at end of file