添加输入密码查询pdf
This commit is contained in:
parent
86750a4429
commit
687ac17419
@ -3,7 +3,6 @@ package com.all.pdfreader.pro.app.room.entity
|
||||
import android.os.Parcelable
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.all.pdfreader.pro.app.ui.dialog.PdfPasswordDialog
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
|
||||
@ -42,7 +42,7 @@ class PdfRepository private constructor(context: Context) {
|
||||
pdfDao.searchDocuments(query)
|
||||
|
||||
suspend fun updateFavoriteStatus(fileHash: String, isFavorite: Boolean) {
|
||||
val document = pdfDao.getByHash(fileHash)?.copy(
|
||||
val document = pdfDao.getByPath(fileHash)?.copy(
|
||||
isFavorite = isFavorite,
|
||||
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) {
|
||||
val document = pdfDao.getByHash(fileHash)?.copy(
|
||||
val document = pdfDao.getByPath(fileHash)?.copy(
|
||||
lastOpenedTime = System.currentTimeMillis(),
|
||||
lastReadPage = page,
|
||||
readingProgress = progress
|
||||
@ -59,14 +59,14 @@ class PdfRepository private constructor(context: Context) {
|
||||
}
|
||||
|
||||
suspend fun updatePasswordStatus(fileHash: String, isPassword: Boolean) {
|
||||
val document = pdfDao.getByHash(fileHash)?.copy(
|
||||
val document = pdfDao.getByPath(fileHash)?.copy(
|
||||
isPassword = isPassword
|
||||
)
|
||||
document?.let { pdfDao.update(it) }
|
||||
}
|
||||
|
||||
suspend fun updatePassword(fileHash: String, password: String?) {
|
||||
val document = pdfDao.getByHash(fileHash)?.copy(
|
||||
val document = pdfDao.getByPath(fileHash)?.copy(
|
||||
password = password
|
||||
)
|
||||
document?.let { pdfDao.update(it) }
|
||||
@ -113,7 +113,7 @@ class PdfRepository private constructor(context: Context) {
|
||||
// 组合查询
|
||||
suspend fun getPdfWithDetails(pdfHash: String): Flow<PdfDetails> {
|
||||
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),
|
||||
bookmarkDao.getBookmarksByPdf(pdfHash),
|
||||
noteDao.getNotesByPdf(pdfHash)
|
||||
|
||||
@ -8,6 +8,7 @@ import androidx.lifecycle.lifecycleScope
|
||||
import com.all.pdfreader.pro.app.R
|
||||
import com.all.pdfreader.pro.app.databinding.ActivityPdfViewBinding
|
||||
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.viewmodel.PdfViewModel
|
||||
import com.github.barteksc.pdfviewer.listener.OnErrorListener
|
||||
@ -19,7 +20,7 @@ import java.io.File
|
||||
class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeListener,
|
||||
OnErrorListener {
|
||||
override val TAG: String = "PdfViewActivity"
|
||||
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_PDF_HASH = "extra_pdf_hash"
|
||||
|
||||
@ -63,32 +64,13 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
|
||||
// 使用传递的文件路径加载PDF
|
||||
val file = File(pdfDocument.filePath)
|
||||
if (file.exists()) {
|
||||
val pdfView = binding.pdfview
|
||||
|
||||
// 如果有密码,先尝试使用密码加载
|
||||
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)
|
||||
return
|
||||
}
|
||||
//需要密码展示对话框。
|
||||
if (pdfDocument.isPassword) {
|
||||
showPasswordDialog(file)
|
||||
return
|
||||
}
|
||||
|
||||
// 无密码PDF正常加载
|
||||
pdfView.fromFile(file)
|
||||
binding.pdfview.fromFile(file)
|
||||
.defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
|
||||
.enableDoubletap(true)// 是否允许双击缩放
|
||||
.onLoad(this)
|
||||
@ -113,22 +95,13 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
|
||||
logDebug("PDF loading error: ${t?.message}")
|
||||
t?.let {
|
||||
val errorMessage = it.message ?: "未知错误"
|
||||
|
||||
// 检查是否是密码相关的错误
|
||||
if (errorMessage.contains("Password") || errorMessage.contains("password")) {
|
||||
// 如果当前没有设置密码,显示密码输入对话框
|
||||
if (pdfDocument.password.isNullOrEmpty()) {
|
||||
val file = File(pdfDocument.filePath)
|
||||
showPasswordDialog(file)
|
||||
} else {
|
||||
// 密码错误,显示密码输入对话框
|
||||
showToast("PDF密码错误")
|
||||
val file = File(pdfDocument.filePath)
|
||||
showPasswordDialog(file)
|
||||
}
|
||||
val file = File(pdfDocument.filePath)
|
||||
showPasswordDialog(file)
|
||||
} else {
|
||||
// 其他错误
|
||||
showToast("PDF加载失败: $errorMessage")
|
||||
showToast(getString(R.string.pdf_loading_failed))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
@ -156,57 +129,23 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
|
||||
}
|
||||
|
||||
private fun showPasswordDialog(file: File) {
|
||||
val builder = android.app.AlertDialog.Builder(this)
|
||||
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)
|
||||
} else {
|
||||
showToast("密码不能为空")
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
builder.setNegativeButton("取消") { dialog, _ ->
|
||||
dialog.cancel()
|
||||
PdfPasswordProtectionDialogFragment(file, onOkClick = { password ->
|
||||
tryLoadPdfWithPassword(file, password)
|
||||
}, onCancelClick = {
|
||||
finish()
|
||||
}
|
||||
|
||||
builder.setOnCancelListener {
|
||||
finish()
|
||||
}
|
||||
|
||||
builder.show()
|
||||
}).show(supportFragmentManager, TAG)
|
||||
}
|
||||
|
||||
|
||||
private fun tryLoadPdfWithPassword(file: File, password: String) {
|
||||
try {
|
||||
binding.pdfview.fromFile(file)
|
||||
.password(password) // 使用输入的密码
|
||||
.defaultPage(pdfDocument.lastReadPage)
|
||||
.enableDoubletap(true)
|
||||
.onLoad(this)
|
||||
.enableAnnotationRendering(true)
|
||||
.onError { error ->
|
||||
logDebug("Password still incorrect: ${error?.message}")
|
||||
showToast("密码错误,请重试")
|
||||
showPasswordDialog(file) // 重新显示密码对话框
|
||||
}
|
||||
.onPageChange(this)
|
||||
.scrollHandle(CustomScrollHandle(this))
|
||||
.load()
|
||||
} catch (e: Exception) {
|
||||
logDebug("Failed to load PDF with provided password: ${e.message}")
|
||||
showToast("密码错误,请重试")
|
||||
showPasswordDialog(file) // 重新显示密码对话框
|
||||
}
|
||||
binding.pdfview.fromFile(file)
|
||||
.password(password) // 使用输入的密码
|
||||
.defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
|
||||
.enableDoubletap(true)// 是否允许双击缩放
|
||||
.onLoad(this)
|
||||
.enableAnnotationRendering(true) // 是否渲染注释(如评论、颜色、表单等)
|
||||
.onError(this)
|
||||
.onPageChange(this)
|
||||
.scrollHandle(CustomScrollHandle(this))
|
||||
.load()
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package com.all.pdfreader.pro.app.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
@ -9,54 +8,58 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.all.pdfreader.pro.app.databinding.DialogPdfPasswordBinding
|
||||
import com.all.pdfreader.pro.app.databinding.DialogPdfSetPasswordBinding
|
||||
|
||||
class PdfPasswordDialog : DialogFragment() {
|
||||
|
||||
private var _binding: DialogPdfPasswordBinding? = null
|
||||
class PdfSetPasswordDialog : DialogFragment() {
|
||||
|
||||
private var _binding: DialogPdfSetPasswordBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private var listener: PasswordDialogListener? = null
|
||||
|
||||
|
||||
interface PasswordDialogListener {
|
||||
fun onPasswordSet(password: String?)
|
||||
fun onPasswordDialogCancelled()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun newInstance(): PdfPasswordDialog {
|
||||
return PdfPasswordDialog()
|
||||
fun newInstance(): PdfSetPasswordDialog {
|
||||
return PdfSetPasswordDialog()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
_binding = DialogPdfPasswordBinding.inflate(inflater, container, false)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = DialogPdfSetPasswordBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
||||
setupListeners()
|
||||
setupTextWatchers()
|
||||
}
|
||||
|
||||
|
||||
private fun setupListeners() {
|
||||
binding.tvCancel.setOnClickListener {
|
||||
listener?.onPasswordDialogCancelled()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
||||
binding.tvConfirm.setOnClickListener {
|
||||
val password = binding.etPassword.text.toString()
|
||||
val confirmPassword = binding.etConfirmPassword.text.toString()
|
||||
|
||||
|
||||
if (validatePassword(password, confirmPassword)) {
|
||||
listener?.onPasswordSet(password)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setupTextWatchers() {
|
||||
binding.etPassword.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
@ -65,7 +68,7 @@ class PdfPasswordDialog : DialogFragment() {
|
||||
validateInput()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
binding.etConfirmPassword.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
@ -74,43 +77,43 @@ class PdfPasswordDialog : DialogFragment() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
private fun validateInput() {
|
||||
val password = binding.etPassword.text.toString()
|
||||
val confirmPassword = binding.etConfirmPassword.text.toString()
|
||||
|
||||
|
||||
binding.tilPassword.error = null
|
||||
binding.tilConfirmPassword.error = null
|
||||
|
||||
|
||||
if (password.isNotEmpty() && confirmPassword.isNotEmpty() && password != confirmPassword) {
|
||||
binding.tilConfirmPassword.error = "密码不匹配"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun validatePassword(password: String, confirmPassword: String): Boolean {
|
||||
binding.tilPassword.error = null
|
||||
binding.tilConfirmPassword.error = null
|
||||
|
||||
|
||||
// 允许空密码(表示不设置密码)
|
||||
if (password.isEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// 密码长度验证
|
||||
if (password.length < 4) {
|
||||
binding.tilPassword.error = "密码长度至少为4位"
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// 密码匹配验证
|
||||
if (password != confirmPassword) {
|
||||
binding.tilConfirmPassword.error = "密码不匹配"
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
if (context is PasswordDialogListener) {
|
||||
@ -119,12 +122,12 @@ class PdfPasswordDialog : DialogFragment() {
|
||||
throw RuntimeException("$context must implement PasswordDialogListener")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
listener = null
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,11 @@
|
||||
package com.all.pdfreader.pro.app.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
|
||||
object AppUtils {
|
||||
|
||||
@ -42,4 +46,16 @@ object AppUtils {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ import android.os.ParcelFileDescriptor
|
||||
import android.provider.MediaStore
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
import com.shockwave.pdfium.PdfiumCore
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
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? {
|
||||
// 先尝试通过 DATA 字段获取
|
||||
val projection = arrayOf(MediaStore.Files.FileColumns.DATA)
|
||||
|
||||
76
app/src/main/res/layout/dialog_pdf_password_protection.xml
Normal file
76
app/src/main/res/layout/dialog_pdf_password_protection.xml
Normal 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>
|
||||
@ -3,43 +3,46 @@
|
||||
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"
|
||||
android:background="@android:color/white">
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="设置PDF密码"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@android:color/black"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:layout_marginBottom="16dp"
|
||||
android:fontFamily="@font/poppins_semibold"
|
||||
android:text="@string/set_pdf_password"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvMessage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="为PDF文件设置保护密码,留空表示不设置密码"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/darker_gray"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:layout_marginBottom="16dp"
|
||||
android:fontFamily="@font/poppins_regular"
|
||||
android:text="@string/set_pdf_password_dialog_desc"
|
||||
android:textColor="@color/black_60"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/tilPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="输入密码"
|
||||
app:passwordToggleEnabled="true"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="@string/enter_password"
|
||||
app:endIconMode="password_toggle"
|
||||
android:layout_marginBottom="8dp">
|
||||
app:passwordToggleEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/etPassword"
|
||||
android:layout_width="match_parent"
|
||||
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>
|
||||
|
||||
@ -47,43 +50,45 @@
|
||||
android:id="@+id/tilConfirmPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="确认密码"
|
||||
app:passwordToggleEnabled="true"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:hint="@string/confirm_password"
|
||||
app:endIconMode="password_toggle"
|
||||
android:layout_marginBottom="24dp">
|
||||
app:passwordToggleEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/etConfirmPassword"
|
||||
android:layout_width="match_parent"
|
||||
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>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
android:gravity="end"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="取消"
|
||||
android:textColor="@color/black"
|
||||
android:padding="12dp"
|
||||
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
|
||||
android:id="@+id/tvConfirm"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="确认"
|
||||
android:textColor="@color/black"
|
||||
android:fontFamily="@font/poppins_medium"
|
||||
android:padding="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless" />
|
||||
android:text="@string/ok"
|
||||
android:textColor="@color/black" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
4
app/src/main/res/values/dimens.xml
Normal file
4
app/src/main/res/values/dimens.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="dialog_margin">16dp</dimen>
|
||||
</resources>
|
||||
@ -28,4 +28,13 @@
|
||||
<string name="unlock">Unlock</string>
|
||||
<string name="eye_protect">Eye Protect</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>
|
||||
Loading…
Reference in New Issue
Block a user