mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Added PDF file viewer
This commit is contained in:
parent
73229f51a1
commit
b6c146f123
6 changed files with 203 additions and 4 deletions
|
|
@ -285,8 +285,8 @@ class ConversationFragment : GenericFragment() {
|
|||
if (repliedMessageId.isNullOrEmpty()) {
|
||||
Log.w("$TAG Chat message [${model.id}] doesn't have a reply to ID!")
|
||||
} else {
|
||||
val originalMessage = adapter.currentList.find {
|
||||
!it.isEvent && (it.model as ChatMessageModel).id == repliedMessageId
|
||||
val originalMessage = adapter.currentList.find { eventLog ->
|
||||
!eventLog.isEvent && (eventLog.model as ChatMessageModel).id == repliedMessageId
|
||||
}
|
||||
if (originalMessage != null) {
|
||||
val position = adapter.currentList.indexOf(originalMessage)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-android
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.linphone.ui.main.viewer.adapter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.linphone.R
|
||||
import org.linphone.ui.main.viewer.viewmodel.FileViewModel
|
||||
|
||||
class PdfPagesListAdapter(private val viewModel: FileViewModel) : RecyclerView.Adapter<PdfPagesListAdapter.PdfPageViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PdfPageViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.file_pdf_viewer_page,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return PdfPageViewHolder(view)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return viewModel.getPagesCount()
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PdfPageViewHolder, position: Int) {
|
||||
holder.bind(position)
|
||||
}
|
||||
|
||||
inner class PdfPageViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||
fun bind(index: Int) {
|
||||
viewModel.loadPdfPageInto(index, view.findViewById(R.id.pdf_image))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package org.linphone.ui.main.viewer.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -11,6 +12,7 @@ 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.adapter.PdfPagesListAdapter
|
||||
import org.linphone.ui.main.viewer.viewmodel.FileViewModel
|
||||
|
||||
@UiThread
|
||||
|
|
@ -23,6 +25,8 @@ class FileViewerFragment : GenericFragment() {
|
|||
|
||||
private lateinit var viewModel: FileViewModel
|
||||
|
||||
private lateinit var adapter: PdfPagesListAdapter
|
||||
|
||||
private val args: FileViewerFragmentArgs by navArgs()
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -54,5 +58,19 @@ class FileViewerFragment : GenericFragment() {
|
|||
binding.setBackClickListener {
|
||||
goBack()
|
||||
}
|
||||
|
||||
viewModel.pdfRendererReadyEvent.observe(viewLifecycleOwner) {
|
||||
it.consume {
|
||||
Log.i("$TAG PDF renderer is ready, attaching adapter to ViewPager")
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
viewModel.screenHeight = displayMetrics.heightPixels
|
||||
viewModel.screenWidth = displayMetrics.widthPixels
|
||||
|
||||
adapter = PdfPagesListAdapter(viewModel)
|
||||
binding.pdfViewPager.adapter = adapter
|
||||
binding.dotsIndicator.attachTo(binding.pdfViewPager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,118 @@
|
|||
package org.linphone.ui.main.viewer.viewmodel
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.pdf.PdfRenderer
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.FileUtils
|
||||
|
||||
class FileViewModel @UiThread constructor() : ViewModel() {
|
||||
companion object {
|
||||
private const val TAG = "[File ViewModel]"
|
||||
}
|
||||
|
||||
val path = MutableLiveData<String>()
|
||||
|
||||
val fileName = MutableLiveData<String>()
|
||||
|
||||
val fullScreenMode = MutableLiveData<Boolean>()
|
||||
|
||||
val isPdf = MutableLiveData<Boolean>()
|
||||
|
||||
val pdfRendererReadyEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
||||
// Below are required for PDF viewer
|
||||
private lateinit var pdfRenderer: PdfRenderer
|
||||
|
||||
var screenWidth: Int = 0
|
||||
var screenHeight: Int = 0
|
||||
// End of PDF viewer required variables
|
||||
|
||||
init {
|
||||
fullScreenMode.value = true
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun loadFile(file: String) {
|
||||
path.postValue(file)
|
||||
val name = FileUtils.getNameFromFilePath(file)
|
||||
fileName.value = name
|
||||
|
||||
val extension = FileUtils.getExtensionFromFileName(name)
|
||||
if (extension == "pdf") {
|
||||
Log.i("$TAG File [$file] seems to be a PDF")
|
||||
isPdf.value = true
|
||||
fullScreenMode.value = false
|
||||
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val input = ParcelFileDescriptor.open(
|
||||
File(file),
|
||||
ParcelFileDescriptor.MODE_READ_ONLY
|
||||
)
|
||||
pdfRenderer = PdfRenderer(input)
|
||||
Log.i("$TAG ${pdfRenderer.pageCount} pages in file $file")
|
||||
pdfRendererReadyEvent.postValue(Event(true))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
path.value = file
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
if (::pdfRenderer.isInitialized) {
|
||||
pdfRenderer.close()
|
||||
}
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun toggleFullScreen() {
|
||||
fullScreenMode.value = fullScreenMode.value != true
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun getPagesCount(): Int {
|
||||
if (::pdfRenderer.isInitialized) {
|
||||
return pdfRenderer.pageCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun loadPdfPageInto(index: Int, view: ImageView) {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val page: PdfRenderer.Page = pdfRenderer.openPage(index)
|
||||
val width = if (screenWidth <= screenHeight) screenWidth else screenHeight
|
||||
val bm = Bitmap.createBitmap(
|
||||
width,
|
||||
(width / page.width * page.height),
|
||||
Bitmap.Config.ARGB_8888
|
||||
)
|
||||
page.render(bm, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
|
||||
page.close()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
view.setImageBitmap(bm)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("$TAG Exception: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,40 @@
|
|||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
coilFile="@{viewModel.path}"
|
||||
android:visibility="@{viewModel.isPdf ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pdf_view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="@{viewModel.isPdf ? View.VISIBLE : View.GONE, default=gone}"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
|
||||
android:id="@+id/dots_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:visibility="@{viewModel.isPdf ? View.VISIBLE : View.GONE, default=gone}"
|
||||
app:dotsColor="@color/gray_main2_200"
|
||||
app:dotsCornerRadius="8dp"
|
||||
app:dotsSize="13dp"
|
||||
app:dotsSpacing="5dp"
|
||||
app:dotsWidthFactor="2.5"
|
||||
app:selectedDotColor="@color/orange_main_500"
|
||||
app:progressMode="false"
|
||||
app:layout_constraintBottom_toTopOf="@id/file_name"
|
||||
app:layout_constraintStart_toStartOf="@id/pdf_view_pager"
|
||||
app:layout_constraintEnd_toEndOf="@id/pdf_view_pager" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:onClick="@{backClickListener}"
|
||||
|
|
@ -105,7 +134,7 @@
|
|||
android:background="@color/white"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:text="nomdufichier.jpg\nenvoyé le 02/05/2023 à 11h05"
|
||||
android:text="@{viewModel.fileName, default=`nomdufichier.jpg\nenvoyé le 02/05/2023 à 11h05`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_main2_400"
|
||||
android:textAlignment="center"
|
||||
|
|
|
|||
5
app/src/main/res/layout/file_pdf_viewer_page.xml
Normal file
5
app/src/main/res/layout/file_pdf_viewer_page.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.github.chrisbanes.photoview.PhotoView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/pdf_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
Loading…
Add table
Reference in a new issue