添加解密工具。优化结果页面。
This commit is contained in:
parent
43ece1be95
commit
b04a8c9142
@ -15,6 +15,7 @@ import com.all.pdfreader.pro.app.model.SortConfig
|
|||||||
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
|
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
|
||||||
import com.all.pdfreader.pro.app.room.repository.PdfRepository
|
import com.all.pdfreader.pro.app.room.repository.PdfRepository
|
||||||
import com.all.pdfreader.pro.app.ui.adapter.PdfAdapter
|
import com.all.pdfreader.pro.app.ui.adapter.PdfAdapter
|
||||||
|
import com.all.pdfreader.pro.app.ui.dialog.PdfRemovePasswordDialog
|
||||||
import com.all.pdfreader.pro.app.ui.dialog.PdfSetPasswordDialog
|
import com.all.pdfreader.pro.app.ui.dialog.PdfSetPasswordDialog
|
||||||
import com.all.pdfreader.pro.app.util.AppUtils.setClickWithAnimation
|
import com.all.pdfreader.pro.app.util.AppUtils.setClickWithAnimation
|
||||||
import com.all.pdfreader.pro.app.util.AppUtils.setOnSingleClickListener
|
import com.all.pdfreader.pro.app.util.AppUtils.setOnSingleClickListener
|
||||||
@ -93,7 +94,14 @@ class PdfPickerActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PdfPickerSource.UNLOCK -> {
|
PdfPickerSource.UNLOCK -> {
|
||||||
|
PdfRemovePasswordDialog(pdf.filePath, onOkClick = { password ->
|
||||||
|
val intent = PdfResultActivity.createIntentLock(
|
||||||
|
this, pdf.filePath, password,
|
||||||
|
PdfPickerSource.UNLOCK
|
||||||
|
)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}).show(supportFragmentManager, "PdfRemovePasswordDialog")
|
||||||
}
|
}
|
||||||
|
|
||||||
PdfPickerSource.TO_IMAGES -> {}
|
PdfPickerSource.TO_IMAGES -> {}
|
||||||
|
|||||||
@ -15,10 +15,10 @@ import com.all.pdfreader.pro.app.databinding.ActivityPdfSplitResultBinding
|
|||||||
import com.all.pdfreader.pro.app.model.PdfPickerSource
|
import com.all.pdfreader.pro.app.model.PdfPickerSource
|
||||||
import com.all.pdfreader.pro.app.model.PdfSelectedPagesItem
|
import com.all.pdfreader.pro.app.model.PdfSelectedPagesItem
|
||||||
import com.all.pdfreader.pro.app.model.PdfSplitResultItem
|
import com.all.pdfreader.pro.app.model.PdfSplitResultItem
|
||||||
import com.all.pdfreader.pro.app.room.repository.PdfRepository
|
|
||||||
import com.all.pdfreader.pro.app.ui.adapter.PdfResultAdapter
|
import com.all.pdfreader.pro.app.ui.adapter.PdfResultAdapter
|
||||||
import com.all.pdfreader.pro.app.ui.dialog.PromptDialogFragment
|
import com.all.pdfreader.pro.app.ui.dialog.PromptDialogFragment
|
||||||
import com.all.pdfreader.pro.app.util.AppUtils
|
import com.all.pdfreader.pro.app.util.AppUtils
|
||||||
|
import com.all.pdfreader.pro.app.util.AppUtils.generateFastThumbnail
|
||||||
import com.all.pdfreader.pro.app.util.FileUtils.toUnderscoreDateTime
|
import com.all.pdfreader.pro.app.util.FileUtils.toUnderscoreDateTime
|
||||||
import com.all.pdfreader.pro.app.util.PdfScanner
|
import com.all.pdfreader.pro.app.util.PdfScanner
|
||||||
import com.all.pdfreader.pro.app.util.PdfSecurityUtils
|
import com.all.pdfreader.pro.app.util.PdfSecurityUtils
|
||||||
@ -111,7 +111,7 @@ class PdfResultActivity : BaseActivity() {
|
|||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if (source == PdfPickerSource.LOCK) {
|
} else if (source == PdfPickerSource.LOCK || source == PdfPickerSource.UNLOCK) {
|
||||||
if (filepath.isEmpty() || password.isEmpty()) {
|
if (filepath.isEmpty() || password.isEmpty()) {
|
||||||
showToast(getString(R.string.pdf_loading_failed))
|
showToast(getString(R.string.pdf_loading_failed))
|
||||||
finish()
|
finish()
|
||||||
@ -166,8 +166,7 @@ class PdfResultActivity : BaseActivity() {
|
|||||||
binding.progressBar.progress = percent
|
binding.progressBar.progress = percent
|
||||||
}
|
}
|
||||||
})?.let { resultFile ->
|
})?.let { resultFile ->
|
||||||
val thumbnails =
|
val thumbnails = generateFastThumbnail(this@PdfResultActivity, resultFile)
|
||||||
AppUtils.generateFastThumbnail(this@PdfResultActivity, resultFile)
|
|
||||||
val result = PdfSplitResultItem(resultFile.absolutePath, thumbnails, false)
|
val result = PdfSplitResultItem(resultFile.absolutePath, thumbnails, false)
|
||||||
pdfScanner.addNewPdfToDatabase(result.filePath, result.thumbnailPath) {
|
pdfScanner.addNewPdfToDatabase(result.filePath, result.thumbnailPath) {
|
||||||
resultList.add(result)
|
resultList.add(result)
|
||||||
@ -198,8 +197,7 @@ class PdfResultActivity : BaseActivity() {
|
|||||||
binding.progressTv.text = "$progressPercent"
|
binding.progressTv.text = "$progressPercent"
|
||||||
}
|
}
|
||||||
})?.let { resultFile ->
|
})?.let { resultFile ->
|
||||||
val thumbnails =
|
val thumbnails = generateFastThumbnail(this@PdfResultActivity, resultFile)
|
||||||
AppUtils.generateFastThumbnail(this@PdfResultActivity, resultFile)
|
|
||||||
val result = PdfSplitResultItem(resultFile.absolutePath, thumbnails, false)
|
val result = PdfSplitResultItem(resultFile.absolutePath, thumbnails, false)
|
||||||
pdfScanner.addNewPdfToDatabase(result.filePath, result.thumbnailPath) {
|
pdfScanner.addNewPdfToDatabase(result.filePath, result.thumbnailPath) {
|
||||||
resultList.add(result)
|
resultList.add(result)
|
||||||
@ -214,11 +212,23 @@ class PdfResultActivity : BaseActivity() {
|
|||||||
binding.progressTv.text = "$progress"
|
binding.progressTv.text = "$progress"
|
||||||
}.let { it ->
|
}.let { it ->
|
||||||
if (it) {
|
if (it) {
|
||||||
PdfRepository.getInstance().updateIsPassword(filepath, true)
|
pdfRepository.updateIsPassword(filepath, true)
|
||||||
}
|
}
|
||||||
val result = PdfSplitResultItem(filePath = filepath, isPassword = true)
|
val result = PdfSplitResultItem(filePath = filepath, isPassword = true)
|
||||||
resultList.add(result)
|
resultList.add(result)
|
||||||
}
|
}
|
||||||
|
} else if (source == PdfPickerSource.UNLOCK) {
|
||||||
|
binding.congratulationsDesc.text = getString(R.string.remove_password_successfully)
|
||||||
|
PdfSecurityUtils.removePasswordFromPdfWithProgress(filepath, password) { progress ->
|
||||||
|
binding.progressTv.text = "$progress"
|
||||||
|
}?.let { it ->
|
||||||
|
val result = PdfSplitResultItem(
|
||||||
|
filePath = filepath,
|
||||||
|
thumbnailPath = it,
|
||||||
|
isPassword = false
|
||||||
|
)
|
||||||
|
resultList.add(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
binding.processingLayout.visibility = View.GONE
|
binding.processingLayout.visibility = View.GONE
|
||||||
@ -227,7 +237,7 @@ class PdfResultActivity : BaseActivity() {
|
|||||||
resultList[0].isSelected = true
|
resultList[0].isSelected = true
|
||||||
}
|
}
|
||||||
adapter.updateAdapter()
|
adapter.updateAdapter()
|
||||||
isProcessing = false//拆分结束
|
isProcessing = false
|
||||||
exitDialog?.dismissAllowingStateLoss()
|
exitDialog?.dismissAllowingStateLoss()
|
||||||
exitDialog = null
|
exitDialog = null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package com.all.pdfreader.pro.app.ui.dialog
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -195,7 +194,9 @@ class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment()
|
|||||||
}
|
}
|
||||||
binding.setPasswordBtn.setOnClickListener {
|
binding.setPasswordBtn.setOnClickListener {
|
||||||
if (pdfDocument.isPassword) {
|
if (pdfDocument.isPassword) {
|
||||||
PdfRemovePasswordDialog().show(parentFragmentManager, "PdfRemovePasswordDialog")
|
PdfRemovePasswordDialog(pdfDocument.filePath, onOkClick = { password ->
|
||||||
|
viewModel.removePassword(pdfDocument.filePath, password)
|
||||||
|
}).show(parentFragmentManager, "PdfRemovePasswordDialog")
|
||||||
} else {
|
} else {
|
||||||
PdfSetPasswordDialog(onOkClick = { password ->
|
PdfSetPasswordDialog(onOkClick = { password ->
|
||||||
viewModel.setPassword(pdfDocument.filePath, password)
|
viewModel.setPassword(pdfDocument.filePath, password)
|
||||||
|
|||||||
@ -7,22 +7,19 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.graphics.drawable.toDrawable
|
import androidx.core.graphics.drawable.toDrawable
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import com.all.pdfreader.pro.app.R
|
import com.all.pdfreader.pro.app.R
|
||||||
import com.all.pdfreader.pro.app.databinding.DialogPdfRemovePasswordBinding
|
import com.all.pdfreader.pro.app.databinding.DialogPdfRemovePasswordBinding
|
||||||
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
|
|
||||||
import com.all.pdfreader.pro.app.util.AppUtils.showKeyboard
|
import com.all.pdfreader.pro.app.util.AppUtils.showKeyboard
|
||||||
import com.all.pdfreader.pro.app.util.FileUtils.isPdfPasswordCorrect
|
import com.all.pdfreader.pro.app.util.FileUtils.isPdfPasswordCorrect
|
||||||
import com.all.pdfreader.pro.app.util.ToastUtils
|
import com.all.pdfreader.pro.app.util.ToastUtils
|
||||||
import com.all.pdfreader.pro.app.viewmodel.PdfViewModel
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class PdfRemovePasswordDialog() : DialogFragment(
|
class PdfRemovePasswordDialog(
|
||||||
|
val filePath: String,
|
||||||
) {
|
val onOkClick: (password: String) -> Unit = {}
|
||||||
|
) :
|
||||||
|
DialogFragment() {
|
||||||
private lateinit var binding: DialogPdfRemovePasswordBinding
|
private lateinit var binding: DialogPdfRemovePasswordBinding
|
||||||
private val viewModel: PdfViewModel by activityViewModels()
|
|
||||||
private lateinit var pdfDocument: PdfDocumentEntity
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
@ -46,14 +43,8 @@ class PdfRemovePasswordDialog() : DialogFragment(
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
viewModel.pdfDocument.value?.let {
|
|
||||||
pdfDocument = it
|
|
||||||
binding.etPassword.showKeyboard()
|
binding.etPassword.showKeyboard()
|
||||||
setupListeners()
|
setupListeners()
|
||||||
} ?: run {
|
|
||||||
showToast(getString(R.string.file_not))
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListeners() {
|
private fun setupListeners() {
|
||||||
@ -63,8 +54,8 @@ class PdfRemovePasswordDialog() : DialogFragment(
|
|||||||
|
|
||||||
binding.tvConfirm.setOnClickListener {
|
binding.tvConfirm.setOnClickListener {
|
||||||
val password = binding.etPassword.text.toString()
|
val password = binding.etPassword.text.toString()
|
||||||
if (isPdfPasswordCorrect(requireActivity(), File(pdfDocument.filePath), password)) {
|
if (isPdfPasswordCorrect(requireActivity(), File(filePath), password)) {
|
||||||
viewModel.removePassword(pdfDocument.filePath, password)
|
onOkClick(password)
|
||||||
dismiss()
|
dismiss()
|
||||||
} else {
|
} else {
|
||||||
binding.tilPassword.error = getString(R.string.incorrect_password)
|
binding.tilPassword.error = getString(R.string.incorrect_password)
|
||||||
|
|||||||
@ -37,5 +37,9 @@ class ToolsFrag : Fragment() {
|
|||||||
val intent = PdfPickerActivity.createIntent(requireActivity(), PdfPickerSource.LOCK)
|
val intent = PdfPickerActivity.createIntent(requireActivity(), PdfPickerSource.LOCK)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
binding.unLockBtn.setOnClickListener {
|
||||||
|
val intent = PdfPickerActivity.createIntent(requireActivity(), PdfPickerSource.UNLOCK)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
package com.all.pdfreader.pro.app.util
|
package com.all.pdfreader.pro.app.util
|
||||||
|
|
||||||
import android.graphics.pdf.PdfDocument
|
import android.graphics.pdf.PdfDocument
|
||||||
|
import com.all.pdfreader.pro.app.PRApp
|
||||||
|
import com.all.pdfreader.pro.app.room.repository.PdfRepository
|
||||||
|
import com.all.pdfreader.pro.app.util.AppUtils.generateFastThumbnail
|
||||||
import com.tom_roush.pdfbox.pdmodel.PDDocument
|
import com.tom_roush.pdfbox.pdmodel.PDDocument
|
||||||
import com.tom_roush.pdfbox.pdmodel.encryption.AccessPermission
|
import com.tom_roush.pdfbox.pdmodel.encryption.AccessPermission
|
||||||
import com.tom_roush.pdfbox.pdmodel.encryption.StandardProtectionPolicy
|
import com.tom_roush.pdfbox.pdmodel.encryption.StandardProtectionPolicy
|
||||||
@ -45,7 +48,6 @@ object PdfSecurityUtils {
|
|||||||
val job = launch {
|
val job = launch {
|
||||||
while (isActive && progress < 98) {
|
while (isActive && progress < 98) {
|
||||||
delay(50)
|
delay(50)
|
||||||
// 专业曲线:前 80%慢,后 20%快
|
|
||||||
progress += when {
|
progress += when {
|
||||||
progress < 80 -> 1 // 前 80% 每次 +1
|
progress < 80 -> 1 // 前 80% 每次 +1
|
||||||
progress < 90 -> 2 // 80~90% 每次 +2
|
progress < 90 -> 2 // 80~90% 每次 +2
|
||||||
@ -63,9 +65,17 @@ object PdfSecurityUtils {
|
|||||||
// 停止假进度
|
// 停止假进度
|
||||||
job.cancel()
|
job.cancel()
|
||||||
|
|
||||||
// 最终完成直接 100%
|
// 最后 98 -> 100 有一个 1 秒左右的平滑视觉过渡
|
||||||
|
val finalStart = progress
|
||||||
|
val finalEnd = 100
|
||||||
|
val steps = (finalEnd - finalStart).coerceAtLeast(2) // 至少两步
|
||||||
|
val delayPerStep = 1000L / steps
|
||||||
|
|
||||||
|
for (p in finalStart..finalEnd) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
onProgress(100)
|
onProgress(p)
|
||||||
|
}
|
||||||
|
delay(delayPerStep)
|
||||||
}
|
}
|
||||||
success
|
success
|
||||||
}
|
}
|
||||||
@ -84,4 +94,61 @@ object PdfSecurityUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun removePasswordFromPdfWithProgress(
|
||||||
|
inputFilePath: String,
|
||||||
|
password: String,
|
||||||
|
onProgress: (Int) -> Unit
|
||||||
|
): String? = withContext(Dispatchers.IO) {
|
||||||
|
var newThumbnail: String? = null
|
||||||
|
var success = false
|
||||||
|
var progress = 0
|
||||||
|
|
||||||
|
// 启动假进度
|
||||||
|
val job = launch {
|
||||||
|
while (isActive && progress < 98) {
|
||||||
|
delay(50)
|
||||||
|
progress += when {
|
||||||
|
progress < 80 -> 1 // 前 80% 每次 +1
|
||||||
|
progress < 90 -> 2 // 80~90% 每次 +2
|
||||||
|
else -> 3 // 90~98% 每次 +3
|
||||||
|
}
|
||||||
|
if (progress > 98) progress = 98
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onProgress(progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行移除密码操作
|
||||||
|
success = removePasswordFromPdf(inputFilePath, password)
|
||||||
|
if (success) {
|
||||||
|
val pdfRepository = PdfRepository.getInstance()
|
||||||
|
pdfRepository.updateIsPassword(inputFilePath, false)
|
||||||
|
newThumbnail = generateFastThumbnail(PRApp.getContext(), File(inputFilePath))
|
||||||
|
val document = pdfRepository.getDocumentByPath(inputFilePath)
|
||||||
|
if (document?.thumbnailPath.isNullOrEmpty()) {
|
||||||
|
if (!newThumbnail.isNullOrEmpty() && inputFilePath != newThumbnail) {
|
||||||
|
pdfRepository.updateThumbnailPath(inputFilePath, newThumbnail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 停止假进度
|
||||||
|
job.cancel()
|
||||||
|
|
||||||
|
// 最后 98 -> 100 平滑过渡 1 秒
|
||||||
|
val finalStart = progress
|
||||||
|
val finalEnd = 100
|
||||||
|
val steps = (finalEnd - finalStart).coerceAtLeast(2)
|
||||||
|
val delayPerStep = 1000L / steps
|
||||||
|
|
||||||
|
for (p in finalStart..finalEnd) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onProgress(p)
|
||||||
|
}
|
||||||
|
delay(delayPerStep)
|
||||||
|
}
|
||||||
|
|
||||||
|
newThumbnail
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user