mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Started image viewer
This commit is contained in:
parent
b585ba7a8b
commit
ad1625dbb3
13 changed files with 276 additions and 19 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<String>()
|
||||
|
||||
val imagesList = MutableLiveData<ArrayList<String>>()
|
||||
val imagesList = MutableLiveData<ArrayList<FileModel>>()
|
||||
|
||||
val firstImage = MutableLiveData<String>()
|
||||
val firstImage = MutableLiveData<FileModel>()
|
||||
|
||||
val dismissLongPressMenuEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
|
|
@ -109,7 +110,7 @@ class ChatMessageModel @WorkerThread constructor(
|
|||
|
||||
var displayableContentFound = false
|
||||
var filesContentCount = 0
|
||||
val imagesPath = arrayListOf<String>()
|
||||
val imagesPath = arrayListOf<FileModel>()
|
||||
|
||||
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" -> {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String>()
|
||||
|
||||
init {
|
||||
path.postValue(file)
|
||||
}
|
||||
|
||||
fun onClick() {
|
||||
onClicked?.invoke(file)
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +83,10 @@ class ConversationViewModel @UiThread constructor() : ViewModel() {
|
|||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
||||
val fileToDisplayEvent: MutableLiveData<Event<String>> by lazy {
|
||||
MutableLiveData<Event<String>>()
|
||||
}
|
||||
|
||||
val chatRoomFoundEvent = MutableLiveData<Event<Boolean>>()
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String>()
|
||||
|
||||
fun loadFile(file: String) {
|
||||
path.postValue(file)
|
||||
}
|
||||
}
|
||||
|
|
@ -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?) {
|
||||
|
|
|
|||
9
app/src/main/res/drawable/download_simple.xml
Normal file
9
app/src/main/res/drawable/download_simple.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="256"
|
||||
android:viewportHeight="256">
|
||||
<path
|
||||
android:pathData="M224,152v56a16,16 0,0 1,-16 16L48,224a16,16 0,0 1,-16 -16L32,152a8,8 0,0 1,16 0v56L208,208L208,152a8,8 0,0 1,16 0ZM122.34,157.66a8,8 0,0 0,11.32 0l40,-40a8,8 0,0 0,-11.32 -11.32L136,132.69L136,40a8,8 0,0 0,-16 0v92.69L93.66,106.34a8,8 0,0 0,-11.32 11.32Z"
|
||||
android:fillColor="#4e6074"/>
|
||||
</vector>
|
||||
|
|
@ -31,16 +31,17 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/single_image"
|
||||
android:onClick="@{() -> model.firstImage.onClick()}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:visibility="@{model.imagesList.size() > 1 || model.firstImage.length() == 0 ? View.GONE : View.VISIBLE}"
|
||||
android:visibility="@{model.imagesList.size() > 1 || model.firstImage.path.length() == 0 ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintTop_toBottomOf="@id/images_grid"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/text_content"
|
||||
app:layout_constraintHeight_max="@dimen/chat_bubble_big_image_max_size"
|
||||
coilBubble="@{model.firstImage}"/>
|
||||
coilBubble="@{model.firstImage.path}"/>
|
||||
|
||||
<org.linphone.ui.main.chat.view.ChatBubbleTextView
|
||||
style="@style/default_text_style"
|
||||
|
|
|
|||
|
|
@ -5,15 +5,16 @@
|
|||
<import type="android.view.View" />
|
||||
<variable
|
||||
name="model"
|
||||
type="String" />
|
||||
type="org.linphone.ui.main.chat.model.FileModel" />
|
||||
</data>
|
||||
|
||||
<ImageView
|
||||
android:onClick="@{() -> model.onClick()}"
|
||||
android:layout_width="88dp"
|
||||
android:layout_height="88dp"
|
||||
android:layout_margin="1dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
coilBubble="@{model}"/>
|
||||
coilBubble="@{model.path}"/>
|
||||
|
||||
</layout>
|
||||
107
app/src/main/res/layout/file_image_viewer_fragment.xml
Normal file
107
app/src/main/res/layout/file_image_viewer_fragment.xml
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
<import type="android.view.View" />
|
||||
<variable
|
||||
name="backClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="shareClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="saveClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="org.linphone.ui.main.viewer.viewmodel.FileViewModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:onClick="@{backClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/caret_left"
|
||||
app:tint="@color/orange_main_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/main_page_title_style"
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/top_bar_height"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="Conversation"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/back"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/share"
|
||||
android:onClick="@{shareClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/share_network"
|
||||
app:tint="@color/orange_main_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toStartOf="@id/save"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save"
|
||||
android:onClick="@{saveClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="15dp"
|
||||
android:src="@drawable/download_simple"
|
||||
app:tint="@color/orange_main_500"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:src="@drawable/illu"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
coilFile="@{viewModel.path}"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:layout_constraintBottom_toTopOf="@id/file_name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/screen_bottom_margin"
|
||||
android:text="nomdufichier.jpg\nenvoyé le 02/05/2023 à 11h05"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_main2_400"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
|
|
@ -29,6 +29,13 @@
|
|||
app:exitAnim="@anim/slide_out_left"
|
||||
app:popEnterAnim="@anim/slide_in_left"
|
||||
app:popExitAnim="@anim/slide_out_right" />
|
||||
<action
|
||||
android:id="@+id/action_conversationFragment_to_fileViewerFragment"
|
||||
app:destination="@id/fileViewerFragment"
|
||||
app:enterAnim="@anim/slide_in_right"
|
||||
app:exitAnim="@anim/slide_out_left"
|
||||
app:popEnterAnim="@anim/slide_in_left"
|
||||
app:popExitAnim="@anim/slide_out_right" />
|
||||
</fragment>
|
||||
|
||||
<action
|
||||
|
|
@ -62,4 +69,14 @@
|
|||
android:label="AddParticipantsFragment"
|
||||
tools:layout="@layout/generic_add_participants_fragment" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fileViewerFragment"
|
||||
android:name="org.linphone.ui.main.viewer.fragment.FileViewerFragment"
|
||||
android:label="FileViewerFragment"
|
||||
tools:layout="@layout/file_image_viewer_fragment">
|
||||
<argument
|
||||
android:name="path"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
|
||||
</navigation>
|
||||
Loading…
Add table
Reference in a new issue