添加移除密码对话框。

This commit is contained in:
ocean 2025-09-11 19:00:43 +08:00
parent aead309db7
commit 9f023a0461
8 changed files with 224 additions and 1 deletions

View File

@ -12,4 +12,8 @@ sealed class FileActionEvent {
data class SetPassword(val status: Status, val success: Boolean? = null) : FileActionEvent() {
enum class Status { START, COMPLETE }
}
data class RemovePassword(val status: Status, val success: Boolean? = null) : FileActionEvent() {
enum class Status { START, COMPLETE }
}
}

View File

@ -123,6 +123,25 @@ class MainActivity : BaseActivity(), PermissionDialogFragment.PermissionCallback
}
}
}
is FileActionEvent.RemovePassword -> {
when (event.status) {
FileActionEvent.RemovePassword.Status.START -> {
progressDialog = ProgressDialogFragment()
progressDialog?.show(supportFragmentManager, "progressDialog")
}
FileActionEvent.RemovePassword.Status.COMPLETE -> {
progressDialog?.dismiss()
progressDialog = null
if (event.success == true) {
showToast(getString(R.string.remove_password_successfully))
} else {
showToast(getString(R.string.remove_password_failed))
}
}
}
}
}
}
}

View File

@ -110,7 +110,7 @@ class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment()
}
binding.setPasswordBtn.setOnClickListener {
if (pdfDocument.isPassword) {
PdfRemovePasswordDialog().show(parentFragmentManager, "PdfRemovePasswordDialog")
} else {
PdfSetPasswordDialog().show(parentFragmentManager, "PdfSetPasswordDialog")
}

View File

@ -0,0 +1,81 @@
package com.all.pdfreader.pro.app.ui.dialog
import android.graphics.Color
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.graphics.drawable.toDrawable
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.DialogPdfRemovePasswordBinding
import com.all.pdfreader.pro.app.databinding.DialogPdfSetPasswordBinding
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.PdfSecurityUtils
import com.all.pdfreader.pro.app.viewmodel.PdfViewModel
import kotlin.getValue
class PdfRemovePasswordDialog() : DialogFragment(
) {
private lateinit var binding: DialogPdfRemovePasswordBinding
private val viewModel: PdfViewModel by activityViewModels()
private lateinit var pdfDocument: PdfDocumentEntity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
binding = DialogPdfRemovePasswordBinding.inflate(layoutInflater)
return binding.root
}
override fun onStart() {
super.onStart()
isCancelable = false
dialog?.window?.apply {
// 去掉系统默认的背景 padding
setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
// 设置宽度为全屏减去 16dp
val margin = resources.getDimensionPixelSize(R.dimen.dialog_margin) // 16dp
val width = resources.displayMetrics.widthPixels - margin * 2
setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.pdfDocument.value?.let {
pdfDocument = it
binding.etPassword.showKeyboard()
setupListeners()
} ?: run {
showToast(getString(R.string.file_not))
dismiss()
}
}
private fun setupListeners() {
binding.tvCancel.setOnClickListener {
dismiss()
}
binding.tvConfirm.setOnClickListener {
val password = binding.etPassword.text.toString()
if (PdfSecurityUtils.isPdfPasswordCorrect(pdfDocument.filePath, password)) {
viewModel.removePassword(pdfDocument.filePath, password)
dismiss()
} else {
binding.tilPassword.error = getString(R.string.incorrect_password)
}
}
}
private fun showToast(message: String) {
Toast.makeText(requireActivity(), message, Toast.LENGTH_SHORT).show()
}
}

View File

@ -41,4 +41,16 @@ object PdfSecurityUtils {
false // 返回解密失败的标志
}
}
fun isPdfPasswordCorrect(filePath: String, password: String): Boolean {
return try {
// 只尝试打开 PDF不读取页面内容
PDDocument.load(File(filePath), password).use { document ->
// 如果能成功打开且不抛异常,则密码正确
true
}
} catch (e: Exception) {
false
}
}
}

View File

@ -151,4 +151,25 @@ class PdfViewModel : ViewModel() {
)
}
}
fun removePassword(filePath: String, password: String) {
viewModelScope.launch {
_fileActionEvent.postValue(FileActionEvent.RemovePassword(FileActionEvent.RemovePassword.Status.START))
val success = withContext(Dispatchers.IO) {
PdfSecurityUtils.removePasswordFromPdf(filePath, password).also {
if (it) {
pdfRepository.updateIsPassword(filePath, false)
}
}
}
_fileActionEvent.postValue(
FileActionEvent.SetPassword(
FileActionEvent.SetPassword.Status.COMPLETE,
success
)
)
}
}
}

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/dr_rounded_corner_12_bg_white"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:fontFamily="@font/poppins_semibold"
android:text="@string/remove_password"
android:textColor="@color/black"
android:textSize="20sp" />
<TextView
android:id="@+id/tvMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:fontFamily="@font/poppins_regular"
android:text="@string/remove_password_dialog_desc"
android:textColor="@color/black_60"
android:textSize="14sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/enter_password"
app:endIconDrawable="@drawable/dr_password_state"
app:endIconMode="password_toggle"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_regular"
android:inputType="textPassword"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal">
<TextView
android:id="@+id/tvCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:fontFamily="@font/poppins_regular"
android:padding="12dp"
android:text="@string/cancel"
android:textColor="@color/black_80"
android:textSize="16sp" />
<TextView
android:id="@+id/tvConfirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_medium"
android:padding="12dp"
android:text="@string/ok"
android:textColor="@color/black"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>

View File

@ -52,6 +52,7 @@
<string name="set_password_successfully">Set Password successfully</string>
<string name="set_password_failed">Set Password failed</string>
<string name="remove_password">Remove Password</string>
<string name="remove_password_dialog_desc">This file will no longer be password protected.</string>
<string name="remove_password_successfully">Remove Password successfully</string>
<string name="remove_password_failed">Remove Password failed</string>
<string name="duplicate_file">Duplicate File</string>