修复firebase崩溃错误,1.0.3(3)
This commit is contained in:
parent
30c04ee7d9
commit
70850c8a2c
@ -16,6 +16,7 @@ import com.all.pdfreader.pdf.reader.ui.dialog.PdfPasswordProtectionDialogFragmen
|
|||||||
import com.all.pdfreader.pdf.reader.util.AppUtils.setOnSingleClickListener
|
import com.all.pdfreader.pdf.reader.util.AppUtils.setOnSingleClickListener
|
||||||
import com.all.pdfreader.pdf.reader.util.FileUtils.isPdfEncrypted
|
import com.all.pdfreader.pdf.reader.util.FileUtils.isPdfEncrypted
|
||||||
import com.all.pdfreader.pdf.reader.util.PdfUtils
|
import com.all.pdfreader.pdf.reader.util.PdfUtils
|
||||||
|
import com.all.pdfreader.pdf.reader.util.ToastUtils
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -55,8 +56,8 @@ class PdfToImageActivity : BaseActivity() {
|
|||||||
statusBarDarkFont(true)
|
statusBarDarkFont(true)
|
||||||
navigationBarColor(R.color.bg_color)
|
navigationBarColor(R.color.bg_color)
|
||||||
}
|
}
|
||||||
filePath = intent.getStringExtra(EXTRA_PDF_PATH)
|
filePath = intent.getStringExtra(EXTRA_PDF_PATH) ?: ""
|
||||||
?: throw IllegalArgumentException("PDF file hash is required")
|
|
||||||
source = getSerializableOrDefault(EXTRA_SOURCE, PdfPickerSource.NONE)
|
source = getSerializableOrDefault(EXTRA_SOURCE, PdfPickerSource.NONE)
|
||||||
if (filePath.isEmpty()) {
|
if (filePath.isEmpty()) {
|
||||||
showToast(getString(R.string.file_not))
|
showToast(getString(R.string.file_not))
|
||||||
@ -153,8 +154,18 @@ class PdfToImageActivity : BaseActivity() {
|
|||||||
PdfUtils.splitPdfToPageItemsFlow(
|
PdfUtils.splitPdfToPageItemsFlow(
|
||||||
context = this@PdfToImageActivity,
|
context = this@PdfToImageActivity,
|
||||||
inputFile = file,
|
inputFile = file,
|
||||||
password = password
|
password = password,
|
||||||
|
onError = { e ->
|
||||||
|
runOnUiThread {
|
||||||
|
ToastUtils.show(
|
||||||
|
this@PdfToImageActivity,
|
||||||
|
getString(R.string.file_not_pdf_or_corrupted)
|
||||||
|
)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
).collect { pageItem ->
|
).collect { pageItem ->
|
||||||
|
|
||||||
logDebug("splitPdfToPageItemsFlow pageItem->$pageItem")
|
logDebug("splitPdfToPageItemsFlow pageItem->$pageItem")
|
||||||
if (pdfPageList.size <= pageItem.pageIndex) {
|
if (pdfPageList.size <= pageItem.pageIndex) {
|
||||||
pdfPageList.add(pageItem)
|
pdfPageList.add(pageItem)
|
||||||
|
|||||||
@ -49,12 +49,12 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
|
|||||||
get() = binding.rootBottomLayout
|
get() = binding.rootBottomLayout
|
||||||
companion object {
|
companion object {
|
||||||
const val FRAG_TAG = "PdfViewActivity"
|
const val FRAG_TAG = "PdfViewActivity"
|
||||||
private const val EXTRA_PDF_HASH = "extra_pdf_hash"
|
private const val EXTRA_PDF_FILE_PATH = "extra_pdf_file_path"
|
||||||
|
|
||||||
// 创建启动Intent的便捷方法
|
// 创建启动Intent的便捷方法
|
||||||
fun createIntent(context: Context, filePath: String): Intent {
|
fun createIntent(context: Context, filePath: String): Intent {
|
||||||
return Intent(context, PdfViewActivity::class.java).apply {
|
return Intent(context, PdfViewActivity::class.java).apply {
|
||||||
putExtra(EXTRA_PDF_HASH, filePath)
|
putExtra(EXTRA_PDF_FILE_PATH, filePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,9 +81,12 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
|
|||||||
navigationBarColor(R.color.white)
|
navigationBarColor(R.color.white)
|
||||||
}
|
}
|
||||||
setupDoubleBackExit()
|
setupDoubleBackExit()
|
||||||
|
val filePath = intent.getStringExtra(EXTRA_PDF_FILE_PATH) ?: ""
|
||||||
|
if (filePath.isEmpty()) {
|
||||||
|
showToast(getString(R.string.file_not))
|
||||||
|
finish()
|
||||||
|
}
|
||||||
initObserve()
|
initObserve()
|
||||||
val filePath = intent.getStringExtra(EXTRA_PDF_HASH)
|
|
||||||
?: throw IllegalArgumentException("PDF file hash is required")
|
|
||||||
// 加载PDF数据
|
// 加载PDF数据
|
||||||
viewModel.getPDFDocument(filePath)
|
viewModel.getPDFDocument(filePath)
|
||||||
//加载书签数据
|
//加载书签数据
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import com.all.pdfreader.pdf.reader.util.AppUtils.setOnSingleClickListener
|
|||||||
import com.all.pdfreader.pdf.reader.util.FileUtils.isPdfEncrypted
|
import com.all.pdfreader.pdf.reader.util.FileUtils.isPdfEncrypted
|
||||||
import com.all.pdfreader.pdf.reader.util.FileUtils.toUnderscoreDateTime
|
import com.all.pdfreader.pdf.reader.util.FileUtils.toUnderscoreDateTime
|
||||||
import com.all.pdfreader.pdf.reader.util.PdfUtils
|
import com.all.pdfreader.pdf.reader.util.PdfUtils
|
||||||
|
import com.all.pdfreader.pdf.reader.util.ToastUtils
|
||||||
import com.gyf.immersionbar.ImmersionBar
|
import com.gyf.immersionbar.ImmersionBar
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -35,7 +36,7 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
get() = binding.rootBottomLayout
|
get() = binding.rootBottomLayout
|
||||||
|
|
||||||
private var currentViewState: ViewState = ViewState.SPLIT_LIST
|
private var currentViewState: ViewState = ViewState.SPLIT_LIST
|
||||||
var currentPassword : String? = null//拆分只会选择一个文件。直接进行密码传递
|
var currentPassword: String? = null//拆分只会选择一个文件。直接进行密码传递
|
||||||
|
|
||||||
private enum class ViewState {
|
private enum class ViewState {
|
||||||
SPLIT_LIST, // 拆分页列表
|
SPLIT_LIST, // 拆分页列表
|
||||||
@ -69,8 +70,7 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
statusBarDarkFont(true)
|
statusBarDarkFont(true)
|
||||||
navigationBarColor(R.color.bg_color)
|
navigationBarColor(R.color.bg_color)
|
||||||
}
|
}
|
||||||
filePath = intent.getStringExtra(EXTRA_PDF_PATH)
|
filePath = intent.getStringExtra(EXTRA_PDF_PATH) ?: ""
|
||||||
?: throw IllegalArgumentException("PDF file hash is required")
|
|
||||||
if (filePath.isEmpty()) {
|
if (filePath.isEmpty()) {
|
||||||
showToast(getString(R.string.file_not))
|
showToast(getString(R.string.file_not))
|
||||||
finish()
|
finish()
|
||||||
@ -174,7 +174,7 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initSplitDataWithPassword(file: File, password: String? = null) {
|
private fun initSplitDataWithPassword(file: File, password: String? = null) {
|
||||||
if(!password.isNullOrEmpty()){
|
if (!password.isNullOrEmpty()) {
|
||||||
currentPassword = password
|
currentPassword = password
|
||||||
}
|
}
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
@ -188,7 +188,16 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
PdfUtils.splitPdfToPageItemsFlow(
|
PdfUtils.splitPdfToPageItemsFlow(
|
||||||
context = this@SplitPdfActivity,
|
context = this@SplitPdfActivity,
|
||||||
inputFile = file,
|
inputFile = file,
|
||||||
password = password
|
password = password,
|
||||||
|
onError = { e ->
|
||||||
|
runOnUiThread {
|
||||||
|
ToastUtils.show(
|
||||||
|
this@SplitPdfActivity,
|
||||||
|
getString(R.string.file_not_pdf_or_corrupted)
|
||||||
|
)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
).collect { pageItem ->
|
).collect { pageItem ->
|
||||||
logDebug("splitPdfToPageItemsFlow pageItem->$pageItem")
|
logDebug("splitPdfToPageItemsFlow pageItem->$pageItem")
|
||||||
if (splitList.size <= pageItem.pageIndex) {
|
if (splitList.size <= pageItem.pageIndex) {
|
||||||
|
|||||||
@ -518,24 +518,10 @@ object FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFileFromUri(context: Context, uri: Uri): File? {
|
fun getFileFromUri(context: Context, uri: Uri): File? {
|
||||||
// 先尝试通过 DATA 字段获取
|
|
||||||
val projection = arrayOf(MediaStore.Files.FileColumns.DATA)
|
|
||||||
context.contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
val path =
|
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA))
|
|
||||||
if (!path.isNullOrEmpty()) {
|
|
||||||
val file = File(path)
|
|
||||||
if (file.exists()) {
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Android 10+ 或 DATA 字段为空时,使用 ContentResolver 流访问
|
|
||||||
return try {
|
return try {
|
||||||
val tempFile = File(context.cacheDir, "temp_pdf_${System.currentTimeMillis()}.pdf")
|
val fileName = getFileName(context, uri) ?: "temp_${System.currentTimeMillis()}"
|
||||||
|
val tempFile = File(context.cacheDir, fileName)
|
||||||
|
|
||||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||||
tempFile.outputStream().use { output ->
|
tempFile.outputStream().use { output ->
|
||||||
input.copyTo(output)
|
input.copyTo(output)
|
||||||
@ -543,11 +529,28 @@ object FileUtils {
|
|||||||
}
|
}
|
||||||
tempFile
|
tempFile
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Log.e("ocean", "无法获取文件: ${e.message}", e)
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getFileName(context: Context, uri: Uri): String? {
|
||||||
|
return try {
|
||||||
|
val cursor = context.contentResolver.query(uri,
|
||||||
|
arrayOf(MediaStore.Files.FileColumns.DISPLAY_NAME),
|
||||||
|
null, null, null)
|
||||||
|
cursor?.use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
return it.getString(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun duplicateFile(originalFile: File): File? {
|
fun duplicateFile(originalFile: File): File? {
|
||||||
if (!originalFile.exists()) return null
|
if (!originalFile.exists()) return null
|
||||||
|
|
||||||
|
|||||||
@ -86,7 +86,8 @@ class PDFSearchManager(private val pdfView: PDFView) {
|
|||||||
onLoaded?.invoke(cachedDoc!!)
|
onLoaded?.invoke(cachedDoc!!)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
onError?.invoke(e)
|
onError?.invoke(e)
|
||||||
throw e
|
cachedDoc = null
|
||||||
|
cachedPath = null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 已缓存文档,仍可调用回调
|
// 已缓存文档,仍可调用回调
|
||||||
|
|||||||
@ -52,53 +52,68 @@ object PdfUtils {
|
|||||||
dpi: Float = 72f,
|
dpi: Float = 72f,
|
||||||
chunkSize: Int = 5,
|
chunkSize: Int = 5,
|
||||||
thumbWidth: Int = 200,
|
thumbWidth: Int = 200,
|
||||||
password: String? = null
|
password: String? = null,
|
||||||
|
onError: ((Exception) -> Unit)? = null
|
||||||
): Flow<PdfPageItem> = flow {
|
): Flow<PdfPageItem> = flow {
|
||||||
val pdfiumCore = PdfiumCore(context)
|
val pdfiumCore = PdfiumCore(context)
|
||||||
ParcelFileDescriptor.open(inputFile, ParcelFileDescriptor.MODE_READ_ONLY).use { fd ->
|
|
||||||
val pdfDocument = if (password.isNullOrEmpty()) {
|
|
||||||
pdfiumCore.newDocument(fd)
|
|
||||||
} else {
|
|
||||||
pdfiumCore.newDocument(fd, password)
|
|
||||||
}
|
|
||||||
|
|
||||||
val pageCount = pdfiumCore.getPageCount(pdfDocument)
|
try {
|
||||||
|
ParcelFileDescriptor.open(inputFile, ParcelFileDescriptor.MODE_READ_ONLY).use { fd ->
|
||||||
val pages = List(pageCount) {
|
val pdfDocument = try {
|
||||||
PdfPageItem(pageIndex = it, previewFilePath = null, isSelected = false)
|
if (password.isNullOrEmpty()) {
|
||||||
}
|
pdfiumCore.newDocument(fd)
|
||||||
|
} else {
|
||||||
// 先 emit 页对象,让 UI 知道总页数
|
pdfiumCore.newDocument(fd, password)
|
||||||
pages.forEach { emit(it) }
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
val cacheDir = File(context.cacheDir, child).apply { mkdirs() }
|
onError?.invoke(e)
|
||||||
|
return@flow // 直接退出 flow,不崩溃
|
||||||
for (i in 0 until pageCount) {
|
|
||||||
pdfiumCore.openPage(pdfDocument, i)
|
|
||||||
|
|
||||||
val width = (pdfiumCore.getPageWidthPoint(pdfDocument, i) * dpi / 72).toInt()
|
|
||||||
val height = (pdfiumCore.getPageHeightPoint(pdfDocument, i) * dpi / 72).toInt()
|
|
||||||
|
|
||||||
val scale = thumbWidth.toFloat() / width
|
|
||||||
val targetHeight = (height * scale).toInt()
|
|
||||||
|
|
||||||
val bitmap = createBitmap(thumbWidth, targetHeight, Bitmap.Config.RGB_565)
|
|
||||||
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, i, 0, 0, thumbWidth, targetHeight)
|
|
||||||
|
|
||||||
// 保存为压缩 JPEG
|
|
||||||
val outFile = File(cacheDir, inputFile.name + "_page_$i.jpg")
|
|
||||||
FileOutputStream(outFile).use { fos ->
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos)
|
|
||||||
}
|
}
|
||||||
bitmap.recycle()
|
|
||||||
|
|
||||||
pages[i].previewFilePath = outFile.absolutePath
|
val pageCount = pdfiumCore.getPageCount(pdfDocument)
|
||||||
emit(pages[i])
|
val pages = List(pageCount) {
|
||||||
|
PdfPageItem(pageIndex = it, previewFilePath = null, isSelected = false)
|
||||||
|
}
|
||||||
|
|
||||||
if ((i + 1) % chunkSize == 0) delay(50) // 分批渲染,保证 UI 流畅
|
// 先 emit 页对象,让 UI 知道总页数
|
||||||
|
pages.forEach { emit(it) }
|
||||||
|
|
||||||
|
val cacheDir = File(context.cacheDir, child).apply { mkdirs() }
|
||||||
|
|
||||||
|
for (i in 0 until pageCount) {
|
||||||
|
try {
|
||||||
|
pdfiumCore.openPage(pdfDocument, i)
|
||||||
|
|
||||||
|
val width = (pdfiumCore.getPageWidthPoint(pdfDocument, i) * dpi / 72).toInt()
|
||||||
|
val height = (pdfiumCore.getPageHeightPoint(pdfDocument, i) * dpi / 72).toInt()
|
||||||
|
|
||||||
|
val scale = thumbWidth.toFloat() / width
|
||||||
|
val targetHeight = (height * scale).toInt()
|
||||||
|
|
||||||
|
val bitmap = createBitmap(thumbWidth, targetHeight, Bitmap.Config.RGB_565)
|
||||||
|
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, i, 0, 0, thumbWidth, targetHeight)
|
||||||
|
|
||||||
|
val outFile = File(cacheDir, inputFile.name + "_page_$i.jpg")
|
||||||
|
FileOutputStream(outFile).use { fos ->
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos)
|
||||||
|
}
|
||||||
|
bitmap.recycle()
|
||||||
|
|
||||||
|
pages[i].previewFilePath = outFile.absolutePath
|
||||||
|
emit(pages[i])
|
||||||
|
|
||||||
|
if ((i + 1) % chunkSize == 0) delay(50)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 单页渲染失败也不崩溃,只提示
|
||||||
|
onError?.invoke(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfiumCore.closeDocument(pdfDocument)
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
pdfiumCore.closeDocument(pdfDocument)
|
// 打开文件失败或 PFDium 异常
|
||||||
|
onError?.invoke(e)
|
||||||
}
|
}
|
||||||
}.flowOn(Dispatchers.IO)
|
}.flowOn(Dispatchers.IO)
|
||||||
|
|
||||||
|
|||||||
@ -193,4 +193,5 @@
|
|||||||
<string name="save_to_album">Save to Album</string>
|
<string name="save_to_album">Save to Album</string>
|
||||||
<string name="one_image_converted">1 image converted</string>
|
<string name="one_image_converted">1 image converted</string>
|
||||||
<string name="number_image_converted">%1$d imagesF converted</string>
|
<string name="number_image_converted">%1$d imagesF converted</string>
|
||||||
|
<string name="file_not_pdf_or_corrupted">File not in PDF format or corrupted</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue
Block a user