添加输入密码查询pdf

This commit is contained in:
ocean 2025-09-08 15:57:47 +08:00
parent 86750a4429
commit 687ac17419
12 changed files with 324 additions and 150 deletions

View File

@ -3,7 +3,6 @@ package com.all.pdfreader.pro.app.room.entity
import android.os.Parcelable import android.os.Parcelable
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.all.pdfreader.pro.app.ui.dialog.PdfPasswordDialog
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize

View File

@ -42,7 +42,7 @@ class PdfRepository private constructor(context: Context) {
pdfDao.searchDocuments(query) pdfDao.searchDocuments(query)
suspend fun updateFavoriteStatus(fileHash: String, isFavorite: Boolean) { suspend fun updateFavoriteStatus(fileHash: String, isFavorite: Boolean) {
val document = pdfDao.getByHash(fileHash)?.copy( val document = pdfDao.getByPath(fileHash)?.copy(
isFavorite = isFavorite, isFavorite = isFavorite,
addedToFavoriteTime = if (isFavorite) System.currentTimeMillis() else null addedToFavoriteTime = if (isFavorite) System.currentTimeMillis() else null
) )
@ -50,7 +50,7 @@ class PdfRepository private constructor(context: Context) {
} }
suspend fun updateReadingProgress(fileHash: String, page: Int, progress: Float) { suspend fun updateReadingProgress(fileHash: String, page: Int, progress: Float) {
val document = pdfDao.getByHash(fileHash)?.copy( val document = pdfDao.getByPath(fileHash)?.copy(
lastOpenedTime = System.currentTimeMillis(), lastOpenedTime = System.currentTimeMillis(),
lastReadPage = page, lastReadPage = page,
readingProgress = progress readingProgress = progress
@ -59,14 +59,14 @@ class PdfRepository private constructor(context: Context) {
} }
suspend fun updatePasswordStatus(fileHash: String, isPassword: Boolean) { suspend fun updatePasswordStatus(fileHash: String, isPassword: Boolean) {
val document = pdfDao.getByHash(fileHash)?.copy( val document = pdfDao.getByPath(fileHash)?.copy(
isPassword = isPassword isPassword = isPassword
) )
document?.let { pdfDao.update(it) } document?.let { pdfDao.update(it) }
} }
suspend fun updatePassword(fileHash: String, password: String?) { suspend fun updatePassword(fileHash: String, password: String?) {
val document = pdfDao.getByHash(fileHash)?.copy( val document = pdfDao.getByPath(fileHash)?.copy(
password = password password = password
) )
document?.let { pdfDao.update(it) } document?.let { pdfDao.update(it) }
@ -113,7 +113,7 @@ class PdfRepository private constructor(context: Context) {
// 组合查询 // 组合查询
suspend fun getPdfWithDetails(pdfHash: String): Flow<PdfDetails> { suspend fun getPdfWithDetails(pdfHash: String): Flow<PdfDetails> {
return combine( return combine(
pdfDao.getByHash(pdfHash)?.let { kotlinx.coroutines.flow.flowOf(it) } pdfDao.getByPath(pdfHash)?.let { kotlinx.coroutines.flow.flowOf(it) }
?: kotlinx.coroutines.flow.flowOf(null), ?: kotlinx.coroutines.flow.flowOf(null),
bookmarkDao.getBookmarksByPdf(pdfHash), bookmarkDao.getBookmarksByPdf(pdfHash),
noteDao.getNotesByPdf(pdfHash) noteDao.getNotesByPdf(pdfHash)

View File

@ -8,6 +8,7 @@ import androidx.lifecycle.lifecycleScope
import com.all.pdfreader.pro.app.R import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.ActivityPdfViewBinding import com.all.pdfreader.pro.app.databinding.ActivityPdfViewBinding
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
import com.all.pdfreader.pro.app.ui.dialog.PdfPasswordProtectionDialogFragment
import com.all.pdfreader.pro.app.ui.view.CustomScrollHandle import com.all.pdfreader.pro.app.ui.view.CustomScrollHandle
import com.all.pdfreader.pro.app.viewmodel.PdfViewModel import com.all.pdfreader.pro.app.viewmodel.PdfViewModel
import com.github.barteksc.pdfviewer.listener.OnErrorListener import com.github.barteksc.pdfviewer.listener.OnErrorListener
@ -63,32 +64,13 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
// 使用传递的文件路径加载PDF // 使用传递的文件路径加载PDF
val file = File(pdfDocument.filePath) val file = File(pdfDocument.filePath)
if (file.exists()) { if (file.exists()) {
val pdfView = binding.pdfview //需要密码展示对话框。
if (pdfDocument.isPassword) {
// 如果有密码,先尝试使用密码加载
if (!pdfDocument.password.isNullOrEmpty()) {
try {
pdfView.fromFile(file)
.password(pdfDocument.password) // 使用密码加载
.defaultPage(pdfDocument.lastReadPage)
.enableDoubletap(true)
.onLoad(this)
.enableAnnotationRendering(true)
.onError(this)
.onPageChange(this)
.scrollHandle(CustomScrollHandle(this))
.load()
return
} catch (e: Exception) {
logDebug("Password protected PDF failed: ${e.message}")
// 密码错误,显示密码输入对话框
showPasswordDialog(file) showPasswordDialog(file)
return return
} }
}
// 无密码PDF正常加载 // 无密码PDF正常加载
pdfView.fromFile(file) binding.pdfview.fromFile(file)
.defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始 .defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
.enableDoubletap(true)// 是否允许双击缩放 .enableDoubletap(true)// 是否允许双击缩放
.onLoad(this) .onLoad(this)
@ -113,22 +95,13 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
logDebug("PDF loading error: ${t?.message}") logDebug("PDF loading error: ${t?.message}")
t?.let { t?.let {
val errorMessage = it.message ?: "未知错误" val errorMessage = it.message ?: "未知错误"
// 检查是否是密码相关的错误 // 检查是否是密码相关的错误
if (errorMessage.contains("Password") || errorMessage.contains("password")) { if (errorMessage.contains("Password") || errorMessage.contains("password")) {
// 如果当前没有设置密码,显示密码输入对话框
if (pdfDocument.password.isNullOrEmpty()) {
val file = File(pdfDocument.filePath) val file = File(pdfDocument.filePath)
showPasswordDialog(file) showPasswordDialog(file)
} else {
// 密码错误,显示密码输入对话框
showToast("PDF密码错误")
val file = File(pdfDocument.filePath)
showPasswordDialog(file)
}
} else { } else {
// 其他错误 // 其他错误
showToast("PDF加载失败: $errorMessage") showToast(getString(R.string.pdf_loading_failed))
finish() finish()
} }
} }
@ -156,57 +129,23 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
} }
private fun showPasswordDialog(file: File) { private fun showPasswordDialog(file: File) {
val builder = android.app.AlertDialog.Builder(this) PdfPasswordProtectionDialogFragment(file, onOkClick = { password ->
builder.setTitle("PDF密码保护")
builder.setMessage("请输入PDF文件密码")
val input = android.widget.EditText(this)
input.inputType = android.text.InputType.TYPE_CLASS_TEXT or android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD
builder.setView(input)
builder.setPositiveButton("确定") { dialog, _ ->
val password = input.text.toString()
if (password.isNotEmpty()) {
// 尝试使用输入的密码重新加载PDF
tryLoadPdfWithPassword(file, password) tryLoadPdfWithPassword(file, password)
} else { }, onCancelClick = {
showToast("密码不能为空")
}
dialog.dismiss()
}
builder.setNegativeButton("取消") { dialog, _ ->
dialog.cancel()
finish() finish()
} }).show(supportFragmentManager, TAG)
builder.setOnCancelListener {
finish()
}
builder.show()
} }
private fun tryLoadPdfWithPassword(file: File, password: String) { private fun tryLoadPdfWithPassword(file: File, password: String) {
try {
binding.pdfview.fromFile(file) binding.pdfview.fromFile(file)
.password(password) // 使用输入的密码 .password(password) // 使用输入的密码
.defaultPage(pdfDocument.lastReadPage) .defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
.enableDoubletap(true) .enableDoubletap(true)// 是否允许双击缩放
.onLoad(this) .onLoad(this)
.enableAnnotationRendering(true) .enableAnnotationRendering(true) // 是否渲染注释(如评论、颜色、表单等)
.onError { error -> .onError(this)
logDebug("Password still incorrect: ${error?.message}")
showToast("密码错误,请重试")
showPasswordDialog(file) // 重新显示密码对话框
}
.onPageChange(this) .onPageChange(this)
.scrollHandle(CustomScrollHandle(this)) .scrollHandle(CustomScrollHandle(this))
.load() .load()
} catch (e: Exception) {
logDebug("Failed to load PDF with provided password: ${e.message}")
showToast("密码错误,请重试")
showPasswordDialog(file) // 重新显示密码对话框
}
} }
} }

View File

@ -0,0 +1,82 @@
package com.all.pdfreader.pro.app.ui.dialog
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import androidx.fragment.app.DialogFragment
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.DialogPdfPasswordProtectionBinding
import com.all.pdfreader.pro.app.databinding.DialogPermissionBinding
import com.all.pdfreader.pro.app.databinding.DialogSortBinding
import com.all.pdfreader.pro.app.model.SortConfig
import com.all.pdfreader.pro.app.model.SortDirection
import com.all.pdfreader.pro.app.model.SortField
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
import com.all.pdfreader.pro.app.sp.AppStore
import com.all.pdfreader.pro.app.ui.act.MainActivity.SortableFragment
import com.all.pdfreader.pro.app.ui.view.CustomPasswordTransformation
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import androidx.core.graphics.drawable.toDrawable
import com.all.pdfreader.pro.app.util.AppUtils.showKeyboard
import com.all.pdfreader.pro.app.util.FileUtils.isPdfPasswordCorrect
import java.io.File
class PdfPasswordProtectionDialogFragment(
private val file: File,
private val onOkClick: (String) -> Unit,
private val onCancelClick: () -> Unit
) : DialogFragment() {
private lateinit var binding: DialogPdfPasswordProtectionBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
binding = DialogPdfPasswordProtectionBinding.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)
binding.etPassword.showKeyboard()
binding.tvCancel.setOnClickListener {
onCancelClick()
dismiss()
}
binding.tvConfirm.setOnClickListener {
val password = binding.etPassword.text.toString()
if(password.isEmpty()){
binding.tilPassword.error = getString(R.string.password_not_empty)
return@setOnClickListener
}
if(isPdfPasswordCorrect(requireActivity(),file,password)){
onOkClick(password)
dismiss()
}else{
binding.tilPassword.error = getString(R.string.incorrect_password)
}
}
}
}

View File

@ -1,6 +1,5 @@
package com.all.pdfreader.pro.app.ui.dialog package com.all.pdfreader.pro.app.ui.dialog
import android.app.Dialog
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
@ -9,11 +8,11 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.all.pdfreader.pro.app.databinding.DialogPdfPasswordBinding import com.all.pdfreader.pro.app.databinding.DialogPdfSetPasswordBinding
class PdfPasswordDialog : DialogFragment() { class PdfSetPasswordDialog : DialogFragment() {
private var _binding: DialogPdfPasswordBinding? = null private var _binding: DialogPdfSetPasswordBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private var listener: PasswordDialogListener? = null private var listener: PasswordDialogListener? = null
@ -23,13 +22,17 @@ class PdfPasswordDialog : DialogFragment() {
} }
companion object { companion object {
fun newInstance(): PdfPasswordDialog { fun newInstance(): PdfSetPasswordDialog {
return PdfPasswordDialog() return PdfSetPasswordDialog()
} }
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(
_binding = DialogPdfPasswordBinding.inflate(inflater, container, false) inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = DialogPdfSetPasswordBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }

View File

@ -0,0 +1,24 @@
package com.all.pdfreader.pro.app.ui.view
import android.text.method.PasswordTransformationMethod
import android.view.View
class CustomPasswordTransformation : PasswordTransformationMethod() {
override fun getTransformation(source: CharSequence, view: View): CharSequence {
return PasswordCharSequence(source)
}
private class PasswordCharSequence(private val mSource: CharSequence) : CharSequence {
override val length: Int
get() = mSource.length
override fun get(index: Int): Char {
// 最后一位显示原字符,其余显示●
return if (index == mSource.length - 1) mSource[index] else '●'
}
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
return mSource.subSequence(startIndex, endIndex)
}
}
}

View File

@ -1,7 +1,11 @@
package com.all.pdfreader.pro.app.util package com.all.pdfreader.pro.app.util
import android.app.Activity
import android.content.Context import android.content.Context
import android.view.View import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
object AppUtils { object AppUtils {
@ -42,4 +46,16 @@ object AppUtils {
return (this * context.resources.displayMetrics.density).toInt() return (this * context.resources.displayMetrics.density).toInt()
} }
/**
* 软键盘弹出
*/
fun EditText.showKeyboard() {
requestFocus()
(context as? Activity)?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
postDelayed({
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}, 200)
}
} }

View File

@ -8,6 +8,7 @@ import android.os.ParcelFileDescriptor
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.OpenableColumns import android.provider.OpenableColumns
import android.util.Log import android.util.Log
import com.shockwave.pdfium.PdfiumCore
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
@ -345,6 +346,22 @@ object FileUtils {
} }
} }
/**
* 判断pdf密码是否正确
*/
fun isPdfPasswordCorrect(context: Context, file: File, password: String): Boolean {
return try {
val descriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
val pdfiumCore = PdfiumCore(context)
val doc = pdfiumCore.newDocument(descriptor, password)
pdfiumCore.closeDocument(doc)
true // 没抛异常说明密码正确
} catch (e: Exception) {
false // 抛异常说明密码错误
}
}
fun getFileFromUri(context: Context, uri: Uri): File? { fun getFileFromUri(context: Context, uri: Uri): File? {
// 先尝试通过 DATA 字段获取 // 先尝试通过 DATA 字段获取
val projection = arrayOf(MediaStore.Files.FileColumns.DATA) val projection = arrayOf(MediaStore.Files.FileColumns.DATA)

View File

@ -0,0 +1,76 @@
<?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/password_protection"
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/password_protection_dialog_desc"
android:textColor="@color/black_80"
android:textSize="14sp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:hint="@string/enter_password"
app:endIconMode="password_toggle"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:textSize="16sp"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_regular"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<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" />
<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" />
</LinearLayout>
</LinearLayout>

View File

@ -3,43 +3,46 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/dr_rounded_corner_12_bg_white"
android:orientation="vertical" android:orientation="vertical"
android:padding="24dp" android:padding="24dp">
android:background="@android:color/white">
<TextView <TextView
android:id="@+id/tvTitle" android:id="@+id/tvTitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="设置PDF密码" android:layout_marginBottom="16dp"
android:textSize="20sp" android:fontFamily="@font/poppins_semibold"
android:textStyle="bold" android:text="@string/set_pdf_password"
android:textColor="@android:color/black" android:textColor="@color/black"
android:layout_marginBottom="16dp" /> android:textSize="20sp" />
<TextView <TextView
android:id="@+id/tvMessage" android:id="@+id/tvMessage"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="为PDF文件设置保护密码留空表示不设置密码" android:layout_marginBottom="16dp"
android:textSize="14sp" android:fontFamily="@font/poppins_regular"
android:textColor="@android:color/darker_gray" android:text="@string/set_pdf_password_dialog_desc"
android:layout_marginBottom="16dp" /> android:textColor="@color/black_60"
android:textSize="14sp" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword" android:id="@+id/tilPassword"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="输入密码" android:layout_marginBottom="8dp"
app:passwordToggleEnabled="true" android:hint="@string/enter_password"
app:endIconMode="password_toggle" app:endIconMode="password_toggle"
android:layout_marginBottom="8dp"> app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword" android:id="@+id/etPassword"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPassword" /> android:fontFamily="@font/poppins_regular"
android:inputType="textPassword"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -47,43 +50,45 @@
android:id="@+id/tilConfirmPassword" android:id="@+id/tilConfirmPassword"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="确认密码" android:layout_marginBottom="24dp"
app:passwordToggleEnabled="true" android:hint="@string/confirm_password"
app:endIconMode="password_toggle" app:endIconMode="password_toggle"
android:layout_marginBottom="24dp"> app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/etConfirmPassword" android:id="@+id/etConfirmPassword"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPassword" /> android:fontFamily="@font/poppins_regular"
android:inputType="textPassword"
android:textSize="14sp" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:gravity="end"
android:gravity="end"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/tvCancel" android:id="@+id/tvCancel"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="取消"
android:textColor="@color/black"
android:padding="12dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:background="?attr/selectableItemBackgroundBorderless" /> android:fontFamily="@font/poppins_regular"
android:padding="12dp"
android:text="@string/cancel"
android:textColor="@color/black_80" />
<TextView <TextView
android:id="@+id/tvConfirm" android:id="@+id/tvConfirm"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="确认" android:fontFamily="@font/poppins_medium"
android:textColor="@color/black"
android:padding="12dp" android:padding="12dp"
android:background="?attr/selectableItemBackgroundBorderless" /> android:text="@string/ok"
android:textColor="@color/black" />
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="dialog_margin">16dp</dimen>
</resources>

View File

@ -28,4 +28,13 @@
<string name="unlock">Unlock</string> <string name="unlock">Unlock</string>
<string name="eye_protect">Eye Protect</string> <string name="eye_protect">Eye Protect</string>
<string name="bookmarks">Bookmarks</string> <string name="bookmarks">Bookmarks</string>
<string name="set_pdf_password">Set PDF Password</string>
<string name="set_pdf_password_dialog_desc">Set a protection password for the PDF file,Leaving it blank means no password is set.</string>
<string name="password_protection">PDF Password Protection</string>
<string name="enter_password">Enter password</string>
<string name="confirm_password">Confirm password</string>
<string name="password_protection_dialog_desc">Please enter the PDF file password</string>
<string name="password_not_empty">Password cannot be empty</string>
<string name="incorrect_password">Incorrect password</string>
<string name="pdf_loading_failed">PDF loading failed</string>
</resources> </resources>