mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 03:18:06 +00:00
Added PDF file preview in conversation (message bubble + documents list)
This commit is contained in:
parent
99936e8f75
commit
808dc92cd7
3 changed files with 82 additions and 14 deletions
|
|
@ -14,6 +14,7 @@ Group changes to describe their impact on the project, as follows:
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added the ability to edit/delete chat messages sent less than 24 hours ago.
|
- Added the ability to edit/delete chat messages sent less than 24 hours ago.
|
||||||
|
- Added PDF preview in conversation (message bubble & documents list)
|
||||||
- Added hover effect when using a mouse (useful for tablets or devices with desktop mode)
|
- Added hover effect when using a mouse (useful for tablets or devices with desktop mode)
|
||||||
- Support right click on some items to open bottom sheet/menu
|
- Support right click on some items to open bottom sheet/menu
|
||||||
- Added toggle speaker action in active call notification
|
- Added toggle speaker action in active call notification
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,11 @@
|
||||||
*/
|
*/
|
||||||
package org.linphone.ui.main.chat.model
|
package org.linphone.ui.main.chat.model
|
||||||
|
|
||||||
|
import android.graphics.pdf.PdfRenderer
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.media.MediaMetadataRetriever.METADATA_KEY_DURATION
|
import android.media.MediaMetadataRetriever.METADATA_KEY_DURATION
|
||||||
import android.media.ThumbnailUtils
|
import android.media.ThumbnailUtils
|
||||||
|
import android.os.ParcelFileDescriptor
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import androidx.annotation.AnyThread
|
import androidx.annotation.AnyThread
|
||||||
import androidx.annotation.UiThread
|
import androidx.annotation.UiThread
|
||||||
|
|
@ -35,6 +37,9 @@ import org.linphone.core.tools.Log
|
||||||
import org.linphone.utils.FileUtils
|
import org.linphone.utils.FileUtils
|
||||||
import org.linphone.utils.TimestampUtils
|
import org.linphone.utils.TimestampUtils
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import androidx.core.graphics.createBitmap
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class FileModel
|
class FileModel
|
||||||
@AnyThread
|
@AnyThread
|
||||||
|
|
@ -97,6 +102,9 @@ class FileModel
|
||||||
if (!isWaitingToBeDownloaded) {
|
if (!isWaitingToBeDownloaded) {
|
||||||
val extension = FileUtils.getExtensionFromFileName(path)
|
val extension = FileUtils.getExtensionFromFileName(path)
|
||||||
isPdf = extension == "pdf"
|
isPdf = extension == "pdf"
|
||||||
|
if (isPdf) {
|
||||||
|
loadPdfPreview()
|
||||||
|
}
|
||||||
|
|
||||||
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
val mime = FileUtils.getMimeTypeFromExtension(extension)
|
||||||
mimeTypeString = mime
|
mimeTypeString = mime
|
||||||
|
|
@ -168,21 +176,65 @@ class FileModel
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnyThread
|
@AnyThread
|
||||||
private fun loadVideoPreview() {
|
private fun loadPdfPreview() {
|
||||||
try {
|
scope.launch {
|
||||||
Log.i("$TAG Try to create an image preview of video file [$path]")
|
withContext(Dispatchers.IO) {
|
||||||
val previewBitmap = ThumbnailUtils.createVideoThumbnail(
|
try {
|
||||||
path,
|
val pdfFileDescriptor = ParcelFileDescriptor.open(
|
||||||
MediaStore.Images.Thumbnails.MINI_KIND
|
File(path),
|
||||||
)
|
ParcelFileDescriptor.MODE_READ_ONLY
|
||||||
if (previewBitmap != null) {
|
)
|
||||||
val previewPath = FileUtils.storeBitmap(previewBitmap, fileName)
|
if (pdfFileDescriptor == null) {
|
||||||
Log.i("$TAG Preview of video file [$path] available at [$previewPath]")
|
Log.e("$TAG Failed to get a file descriptor for PDF at [$path]")
|
||||||
mediaPreview.postValue(previewPath)
|
return@withContext
|
||||||
mediaPreviewAvailable.postValue(true)
|
}
|
||||||
|
|
||||||
|
val pdfRenderer = PdfRenderer(pdfFileDescriptor)
|
||||||
|
val pdfFirstPage = pdfRenderer.openPage(0)
|
||||||
|
val previewBitmap = createBitmap(pdfFirstPage.width, pdfFirstPage.height)
|
||||||
|
pdfFirstPage.render(
|
||||||
|
previewBitmap,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY
|
||||||
|
)
|
||||||
|
|
||||||
|
val previewPath = FileUtils.storeBitmap(previewBitmap, fileName)
|
||||||
|
Log.i("$TAG Preview of PDF file [$path] available at [$previewPath]")
|
||||||
|
mediaPreview.postValue(previewPath)
|
||||||
|
mediaPreviewAvailable.postValue(true)
|
||||||
|
|
||||||
|
previewBitmap.recycle()
|
||||||
|
pdfFirstPage.close()
|
||||||
|
pdfRenderer.close()
|
||||||
|
pdfFileDescriptor.close()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("$TAG Failed to get image preview for PDF file [$path]: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AnyThread
|
||||||
|
private fun loadVideoPreview() {
|
||||||
|
scope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
Log.i("$TAG Try to create an image preview of video file [$path]")
|
||||||
|
val previewBitmap = ThumbnailUtils.createVideoThumbnail(
|
||||||
|
path,
|
||||||
|
MediaStore.Images.Thumbnails.MINI_KIND
|
||||||
|
)
|
||||||
|
if (previewBitmap != null) {
|
||||||
|
val previewPath = FileUtils.storeBitmap(previewBitmap, fileName)
|
||||||
|
Log.i("$TAG Preview of video file [$path] available at [$previewPath]")
|
||||||
|
mediaPreview.postValue(previewPath)
|
||||||
|
mediaPreviewAvailable.postValue(true)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("$TAG Failed to get image preview for file [$path]: $e")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("$TAG Failed to get image preview for file [$path]: $e")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,21 @@
|
||||||
app:layout_constraintEnd_toEndOf="@id/left_background"
|
app:layout_constraintEnd_toEndOf="@id/left_background"
|
||||||
app:tint="?attr/color_main2_600" />
|
app:tint="?attr/color_main2_600" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/file_pdf_preview"
|
||||||
|
android:layout_width="@dimen/chat_bubble_grid_file_size"
|
||||||
|
android:layout_height="@dimen/chat_bubble_grid_file_size"
|
||||||
|
android:onClick="@{() -> model.onClick()}"
|
||||||
|
android:onLongClick="@{onLongClickListener}"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:contentDescription="@string/content_description_chat_bubble_file"
|
||||||
|
android:visibility="@{model.isPdf && model.mediaPreviewAvailable ? View.VISIBLE : View.GONE, default=gone}"
|
||||||
|
coilBubbleGrid="@{model.mediaPreview}"
|
||||||
|
coilBubbleFallback="@{fileIcon}"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
style="@style/default_text_style_600"
|
style="@style/default_text_style_600"
|
||||||
android:id="@+id/audio_duration"
|
android:id="@+id/audio_duration"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue