Improved PDF file viewer

This commit is contained in:
Sylvain Berfini 2021-04-01 12:16:42 +02:00
parent 7b23edd393
commit bef62ce2b3
5 changed files with 90 additions and 63 deletions

View file

@ -0,0 +1,54 @@
/*
* 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.activities.main.files.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import org.linphone.R
import org.linphone.activities.main.files.viewmodels.PdfFileViewModel
import org.linphone.databinding.PdfViewerCellBinding
class PdfPagesListAdapter(private val pdfViewModel: PdfFileViewModel) : RecyclerView.Adapter<PdfPagesListAdapter.PdfPageViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PdfPageViewHolder {
val binding: PdfViewerCellBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.pdf_viewer_cell, parent, false
)
return PdfPageViewHolder(binding)
}
override fun getItemCount(): Int {
return pdfViewModel.getPagesCount()
}
override fun onBindViewHolder(holder: PdfPageViewHolder, position: Int) {
holder.bind(position)
}
inner class PdfPageViewHolder(private val binding: PdfViewerCellBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(index: Int) {
with(binding) {
pdfViewModel.loadPdfPageInto(index, pdfImage)
}
}
}
}

View file

@ -22,6 +22,7 @@ package org.linphone.activities.main.files.fragments
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import org.linphone.R import org.linphone.R
import org.linphone.activities.main.files.adapters.PdfPagesListAdapter
import org.linphone.activities.main.files.viewmodels.PdfFileViewModel import org.linphone.activities.main.files.viewmodels.PdfFileViewModel
import org.linphone.activities.main.files.viewmodels.PdfFileViewModelFactory import org.linphone.activities.main.files.viewmodels.PdfFileViewModelFactory
import org.linphone.activities.main.fragments.SecureFragment import org.linphone.activities.main.fragments.SecureFragment
@ -31,6 +32,7 @@ import org.linphone.databinding.PdfViewerFragmentBinding
class PdfViewerFragment : SecureFragment<PdfViewerFragmentBinding>() { class PdfViewerFragment : SecureFragment<PdfViewerFragmentBinding>() {
private lateinit var viewModel: PdfFileViewModel private lateinit var viewModel: PdfFileViewModel
private lateinit var sharedViewModel: SharedMainViewModel private lateinit var sharedViewModel: SharedMainViewModel
private lateinit var adapter: PdfPagesListAdapter
override fun getLayoutId(): Int = R.layout.pdf_viewer_fragment override fun getLayoutId(): Int = R.layout.pdf_viewer_fragment
@ -56,5 +58,9 @@ class PdfViewerFragment : SecureFragment<PdfViewerFragmentBinding>() {
binding.viewModel = viewModel binding.viewModel = viewModel
isSecure = arguments?.getBoolean("Secure") ?: false isSecure = arguments?.getBoolean("Secure") ?: false
adapter = PdfPagesListAdapter(viewModel)
binding.pdfViewPager.adapter = adapter
adapter.notifyDataSetChanged()
} }
} }

View file

@ -22,14 +22,11 @@ package org.linphone.activities.main.files.viewmodels
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.pdf.PdfRenderer import android.graphics.pdf.PdfRenderer
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.widget.ImageView
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import java.io.File import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
@ -45,8 +42,6 @@ class PdfFileViewModelFactory(private val filePath: String) :
class PdfFileViewModel(filePath: String) : ViewModel() { class PdfFileViewModel(filePath: String) : ViewModel() {
val operationInProgress = MutableLiveData<Boolean>() val operationInProgress = MutableLiveData<Boolean>()
val pages = MutableLiveData<ArrayList<PdfPageViewModel>>()
private val pdfRenderer: PdfRenderer private val pdfRenderer: PdfRenderer
init { init {
@ -55,25 +50,21 @@ class PdfFileViewModel(filePath: String) : ViewModel() {
val input = ParcelFileDescriptor.open(File(filePath), ParcelFileDescriptor.MODE_READ_ONLY) val input = ParcelFileDescriptor.open(File(filePath), ParcelFileDescriptor.MODE_READ_ONLY)
pdfRenderer = PdfRenderer(input) pdfRenderer = PdfRenderer(input)
Log.i("[PDF Viewer] ${pdfRenderer.pageCount} pages in file $filePath") Log.i("[PDF Viewer] ${pdfRenderer.pageCount} pages in file $filePath")
loadPdf()
} }
override fun onCleared() { override fun onCleared() {
for (page in pages.value.orEmpty()) { pdfRenderer.close()
page.destroy()
}
pages.value?.clear()
super.onCleared() super.onCleared()
} }
private fun loadPdf() { fun getPagesCount(): Int {
viewModelScope.launch { return pdfRenderer.pageCount
withContext(Dispatchers.IO) { }
try {
operationInProgress.postValue(true) fun loadPdfPageInto(index: Int, view: ImageView) {
try {
operationInProgress.value = true
for (index in 0 until pdfRenderer.pageCount) {
val page: PdfRenderer.Page = pdfRenderer.openPage(index) val page: PdfRenderer.Page = pdfRenderer.openPage(index)
val width = if (coreContext.screenWidth <= coreContext.screenHeight) coreContext.screenWidth else coreContext.screenHeight val width = if (coreContext.screenWidth <= coreContext.screenHeight) coreContext.screenWidth else coreContext.screenHeight
val bm = Bitmap.createBitmap( val bm = Bitmap.createBitmap(
@ -84,25 +75,12 @@ class PdfFileViewModel(filePath: String) : ViewModel() {
page.render(bm, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) page.render(bm, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
page.close() page.close()
val pageViewModel = PdfPageViewModel(bm) view.setImageBitmap(bm)
val list = arrayListOf<PdfPageViewModel>()
list.addAll(pages.value.orEmpty())
list.add(pageViewModel)
pages.postValue(list)
}
operationInProgress.postValue(false) operationInProgress.value = false
} catch (e: Exception) { } catch (e: Exception) {
Log.e("[PDF Viewer] Exception: $e") Log.e("[PDF Viewer] Exception: $e")
operationInProgress.postValue(false) operationInProgress.value = false
}
}
}
}
class PdfPageViewModel(val bitmap: Bitmap) {
fun destroy() {
bitmap.recycle()
} }
} }
} }

View file

@ -3,20 +3,17 @@
<data> <data>
<import type="android.view.View"/> <import type="android.view.View"/>
<variable
name="data"
type="org.linphone.activities.main.files.viewmodels.PdfFileViewModel.PdfPageViewModel" />
</data> </data>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="match_parent">
<ImageView <ImageView
android:id="@+id/pdf_image"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true" />
android:src="@{data.bitmap}" />
</RelativeLayout> </RelativeLayout>

View file

@ -23,19 +23,11 @@
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
tools:layout="@layout/file_viewer_top_bar_fragment" /> tools:layout="@layout/file_viewer_top_bar_fragment" />
<ScrollView <androidx.viewpager2.widget.ViewPager2
android:id="@+id/pdf_view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@id/top_bar_fragment"> android:layout_below="@id/top_bar_fragment" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
bind:entries="@{viewModel.pages}"
bind:layout="@{@layout/pdf_viewer_cell}"/>
</ScrollView>
<include <include
layout="@layout/wait_layout" layout="@layout/wait_layout"