显示pdf
This commit is contained in:
parent
9b5cd5e014
commit
daaa2e4de5
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@ -1,7 +1,10 @@
|
|||||||
|
import org.gradle.kotlin.dsl.implementation
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.devtools.ksp)
|
alias(libs.plugins.devtools.ksp)
|
||||||
|
id("kotlin-parcelize")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -54,4 +57,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.room.runtime)
|
implementation(libs.androidx.room.runtime)
|
||||||
ksp(libs.androidx.room.compiler)
|
ksp(libs.androidx.room.compiler)
|
||||||
implementation(libs.androidx.room.ktx)
|
implementation(libs.androidx.room.ktx)
|
||||||
|
implementation(libs.glide)
|
||||||
|
implementation(libs.androidpdfviewer)
|
||||||
|
implementation(libs.pdfbox.android)
|
||||||
}
|
}
|
||||||
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@ -18,4 +18,6 @@
|
|||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-keep class com.shockwave.**
|
||||||
@ -4,14 +4,15 @@
|
|||||||
|
|
||||||
<!-- Android 11+ 存储权限 -->
|
<!-- Android 11+ 存储权限 -->
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<!-- Android 13+ 媒体权限 -->
|
<!-- Android 13+ 媒体权限 -->
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
|
|
||||||
<!-- 读取所有文件权限(Android 11+ 需要特殊处理) -->
|
<!-- 读取所有文件权限(Android 11+ 需要特殊处理) -->
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
<uses-permission
|
||||||
|
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||||
tools:ignore="ScopedStorage" />
|
tools:ignore="ScopedStorage" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
@ -21,12 +22,12 @@
|
|||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:requestLegacyExternalStorage="true"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.PDFReaderPro"
|
android:theme="@style/Theme.PDFReaderPro"
|
||||||
android:requestLegacyExternalStorage="true"
|
|
||||||
tools:targetApi="36">
|
tools:targetApi="36">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.act.SplashActivity"
|
android:name=".ui.act.SplashActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
@ -42,13 +43,20 @@
|
|||||||
android:name=".ui.act.MainActivity"
|
android:name=".ui.act.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.PDFReaderPro" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ui.act.PdfViewActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.PDFReaderPro">
|
android:theme="@style/Theme.PDFReaderPro">
|
||||||
|
|
||||||
<!-- 处理PDF文件打开 -->
|
<!-- 处理PDF文件打开 -->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:mimeType="application/pdf" />
|
<data android:mimeType="application/pdf" />
|
||||||
<data android:scheme="file" />
|
<data android:scheme="file" />
|
||||||
<data android:scheme="content" />
|
<data android:scheme="content" />
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package com.all.pdfreader.pro.app.room.entity
|
package com.all.pdfreader.pro.app.room.entity
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
@Entity(tableName = "pdf_documents")
|
@Entity(tableName = "pdf_documents")
|
||||||
data class PdfDocumentEntity(
|
data class PdfDocumentEntity(
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@ -28,4 +31,4 @@ data class PdfDocumentEntity(
|
|||||||
val metadataKeywords: String? = null, // PDF元数据关键词
|
val metadataKeywords: String? = null, // PDF元数据关键词
|
||||||
val metadataCreationDate: Long? = null, // PDF创建时间
|
val metadataCreationDate: Long? = null, // PDF创建时间
|
||||||
val metadataModificationDate: Long? = null // PDF修改时间
|
val metadataModificationDate: Long? = null // PDF修改时间
|
||||||
)
|
): Parcelable
|
||||||
@ -4,11 +4,13 @@ import android.app.Activity
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.all.pdfreader.pro.app.room.repository.PdfRepository
|
import com.all.pdfreader.pro.app.room.repository.PdfRepository
|
||||||
import com.all.pdfreader.pro.app.sp.AppStore
|
import com.all.pdfreader.pro.app.sp.AppStore
|
||||||
import com.all.pdfreader.pro.app.util.StoragePermissionHelper
|
import com.all.pdfreader.pro.app.util.StoragePermissionHelper
|
||||||
|
import com.tom_roush.pdfbox.contentstream.operator.text.ShowText
|
||||||
|
|
||||||
abstract class BaseActivity : AppCompatActivity() {
|
abstract class BaseActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@ -60,6 +62,10 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||||||
Log.w("ocean", "$TAG: $message")
|
Log.w("ocean", "$TAG: $message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun showToast(message: String) {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
//获取数据库实例
|
//获取数据库实例
|
||||||
protected fun getRepository(): PdfRepository {
|
protected fun getRepository(): PdfRepository {
|
||||||
return PdfRepository.getInstance()
|
return PdfRepository.getInstance()
|
||||||
|
|||||||
@ -0,0 +1,100 @@
|
|||||||
|
package com.all.pdfreader.pro.app.ui.act
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
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.github.barteksc.pdfviewer.listener.OnErrorListener
|
||||||
|
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener
|
||||||
|
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeListener,
|
||||||
|
OnErrorListener {
|
||||||
|
override val TAG: String = "PdfViewActivity"
|
||||||
|
|
||||||
|
private lateinit var binding: ActivityPdfViewBinding
|
||||||
|
private lateinit var pdfDocument: PdfDocumentEntity
|
||||||
|
private val pdfRepository = getRepository()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityPdfViewBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
// 获取传递的PDF文档数据
|
||||||
|
pdfDocument = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
intent.getParcelableExtra(EXTRA_PDF_DOCUMENT, PdfDocumentEntity::class.java)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION") intent.getParcelableExtra<PdfDocumentEntity>(EXTRA_PDF_DOCUMENT)
|
||||||
|
} ?: throw IllegalArgumentException("PDF document data is required")
|
||||||
|
|
||||||
|
loadPdf()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadPdf() {
|
||||||
|
// 使用传递的文件路径加载PDF
|
||||||
|
val file = File(pdfDocument.filePath)
|
||||||
|
if (file.exists()) {
|
||||||
|
binding.pdfview
|
||||||
|
.fromFile(file)
|
||||||
|
.defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
|
||||||
|
.enableDoubletap(true)// 是否允许双击缩放
|
||||||
|
.onLoad(this)
|
||||||
|
.enableAnnotationRendering(true) // 是否渲染注释(如评论、颜色、表单等)
|
||||||
|
.onError(this)
|
||||||
|
.onPageChange(this)
|
||||||
|
.load()
|
||||||
|
} else {
|
||||||
|
showToast(getString(R.string.file_not) + ": ${pdfDocument.fileName}")
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//PDF 文档加载完成时回调
|
||||||
|
override fun loadComplete(nbPages: Int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//PDF 加载出错时回调
|
||||||
|
override fun onError(t: Throwable?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//页面切换时回调
|
||||||
|
override fun onPageChanged(page: Int, pageCount: Int) {
|
||||||
|
// 保存阅读进度
|
||||||
|
pdfDocument = pdfDocument.copy(
|
||||||
|
lastReadPage = page, readingProgress = (page.toFloat() / pageCount.toFloat()) * 100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
saveReadingProgress()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveReadingProgress() {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
pdfRepository.updateReadingProgress(
|
||||||
|
pdfDocument.fileHash, pdfDocument.lastReadPage, pdfDocument.readingProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val EXTRA_PDF_DOCUMENT = "extra_pdf_document"
|
||||||
|
|
||||||
|
// 创建启动Intent的便捷方法
|
||||||
|
fun createIntent(context: Context, pdfDocument: PdfDocumentEntity): Intent {
|
||||||
|
return Intent(context, PdfViewActivity::class.java).apply {
|
||||||
|
putExtra(EXTRA_PDF_DOCUMENT, pdfDocument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,8 +6,12 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.all.pdfreader.pro.app.databinding.AdapterPdfItemBinding
|
import com.all.pdfreader.pro.app.databinding.AdapterPdfItemBinding
|
||||||
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
|
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
|
||||||
|
import com.all.pdfreader.pro.app.util.AppUtils.dpToPx
|
||||||
import com.all.pdfreader.pro.app.util.FileUtils.toFormatFileSize
|
import com.all.pdfreader.pro.app.util.FileUtils.toFormatFileSize
|
||||||
import com.all.pdfreader.pro.app.util.FileUtils.toSlashDate
|
import com.all.pdfreader.pro.app.util.FileUtils.toSlashDate
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
|
|
||||||
class PdfAdapter(
|
class PdfAdapter(
|
||||||
private var pdfList: MutableList<PdfDocumentEntity>,
|
private var pdfList: MutableList<PdfDocumentEntity>,
|
||||||
@ -30,6 +34,9 @@ class PdfAdapter(
|
|||||||
holder.binding.tvFileName.text = item.fileName
|
holder.binding.tvFileName.text = item.fileName
|
||||||
holder.binding.tvFileSize.text = item.fileSize.toFormatFileSize()
|
holder.binding.tvFileSize.text = item.fileSize.toFormatFileSize()
|
||||||
holder.binding.tvFileDate.text = item.lastModified.toSlashDate()
|
holder.binding.tvFileDate.text = item.lastModified.toSlashDate()
|
||||||
|
Glide.with(holder.binding.root).load(item.thumbnailPath)
|
||||||
|
.transform(CenterCrop(), RoundedCorners(8.dpToPx(holder.binding.root.context)))
|
||||||
|
.into(holder.binding.tvFileImg)
|
||||||
|
|
||||||
holder.binding.root.setOnClickListener {
|
holder.binding.root.setOnClickListener {
|
||||||
onItemClick(item)
|
onItemClick(item)
|
||||||
|
|||||||
@ -14,6 +14,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.act.MainActivity
|
import com.all.pdfreader.pro.app.ui.act.MainActivity
|
||||||
|
import com.all.pdfreader.pro.app.ui.act.PdfViewActivity
|
||||||
import com.all.pdfreader.pro.app.ui.adapter.PdfAdapter
|
import com.all.pdfreader.pro.app.ui.adapter.PdfAdapter
|
||||||
import com.all.pdfreader.pro.app.util.PdfScanner
|
import com.all.pdfreader.pro.app.util.PdfScanner
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -37,7 +38,9 @@ class HomeFrag : BaseFrag(), MainActivity.SortableFragment {
|
|||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
adapter = PdfAdapter(pdfList = mutableListOf(), onItemClick = { pdf ->
|
adapter = PdfAdapter(pdfList = mutableListOf(), onItemClick = { pdf ->
|
||||||
Toast.makeText(requireContext(), "点击: ${pdf.fileName}", Toast.LENGTH_SHORT).show()
|
val intent = PdfViewActivity.createIntent(requireContext(), pdf)
|
||||||
|
startActivity(intent)
|
||||||
|
|
||||||
}, onMoreClick = { pdf ->
|
}, onMoreClick = { pdf ->
|
||||||
Toast.makeText(requireContext(), "更多操作: ${pdf.fileName}", Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), "更多操作: ${pdf.fileName}", Toast.LENGTH_SHORT).show()
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.all.pdfreader.pro.app.util
|
package com.all.pdfreader.pro.app.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
||||||
object AppUtils {
|
object AppUtils {
|
||||||
@ -36,4 +37,9 @@ object AppUtils {
|
|||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Int.dpToPx(context: Context): Int {
|
||||||
|
return (this * context.resources.displayMetrics.density).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,29 +3,17 @@ package com.all.pdfreader.pro.app.util
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
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 android.webkit.MimeTypeMap
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import com.all.pdfreader.pro.app.util.StoragePermissionHelper
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.time.Instant
|
|
||||||
import java.time.ZoneId
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
object FileUtils {
|
object FileUtils {
|
||||||
|
|
||||||
private val PDF_MIME_TYPES = setOf(
|
|
||||||
"application/pdf", "application/x-pdf"
|
|
||||||
)
|
|
||||||
|
|
||||||
fun scanPdfFiles(context: Context): List<File> {
|
fun scanPdfFiles(context: Context): List<File> {
|
||||||
val pdfFiles = mutableListOf<File>()
|
val pdfFiles = mutableListOf<File>()
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package com.all.pdfreader.pro.app.util
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
import android.graphics.pdf.PdfRenderer
|
import android.graphics.pdf.PdfRenderer
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@ -13,6 +15,8 @@ import java.io.File
|
|||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import androidx.core.graphics.createBitmap
|
import androidx.core.graphics.createBitmap
|
||||||
|
import com.github.barteksc.pdfviewer.PDFView
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
class PdfScanner(
|
class PdfScanner(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@ -32,16 +36,28 @@ class PdfScanner(
|
|||||||
|
|
||||||
// 扫描应用私有目录(无需权限)
|
// 扫描应用私有目录(无需权限)
|
||||||
val privateFiles = FileUtils.scanPdfFiles(context)
|
val privateFiles = FileUtils.scanPdfFiles(context)
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 📁 应用私有目录找到: ${privateFiles.size} 个PDF文件")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 📁 应用私有目录找到: ${privateFiles.size} 个PDF文件"
|
||||||
|
)
|
||||||
privateFiles.forEach { file ->
|
privateFiles.forEach { file ->
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 📄 ${file.name} (${FileUtils.formatFileSize(file.length())})")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 📄 ${file.name} (${FileUtils.formatFileSize(file.length())})"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 扫描MediaStore(需要权限)
|
// 扫描MediaStore(需要权限)
|
||||||
val mediaStoreFiles = FileUtils.scanPdfFilesFromMediaStore(context)
|
val mediaStoreFiles = FileUtils.scanPdfFilesFromMediaStore(context)
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 📱 MediaStore找到: ${mediaStoreFiles.size} 个PDF文件")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 📱 MediaStore找到: ${mediaStoreFiles.size} 个PDF文件"
|
||||||
|
)
|
||||||
mediaStoreFiles.forEach { file ->
|
mediaStoreFiles.forEach { file ->
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 📱 ${file.name} (${FileUtils.formatFileSize(file.length())})")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 📱 ${file.name} (${FileUtils.formatFileSize(file.length())})"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合并并去重
|
// 合并并去重
|
||||||
@ -50,7 +66,10 @@ class PdfScanner(
|
|||||||
|
|
||||||
// 处理每个PDF文件
|
// 处理每个PDF文件
|
||||||
allFiles.forEachIndexed { index, file ->
|
allFiles.forEachIndexed { index, file ->
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 🔄 处理文件 ${index + 1}/${allFiles.size}: ${file.name}")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 🔄 处理文件 ${index + 1}/${allFiles.size}: ${file.name}"
|
||||||
|
)
|
||||||
|
|
||||||
if (FileUtils.isPdfFile(file)) {
|
if (FileUtils.isPdfFile(file)) {
|
||||||
val fileHash = FileUtils.calculateFileHash(file.absolutePath)
|
val fileHash = FileUtils.calculateFileHash(file.absolutePath)
|
||||||
@ -60,7 +79,10 @@ class PdfScanner(
|
|||||||
val existingDoc = pdfRepository.getDocumentByHash(fileHash)
|
val existingDoc = pdfRepository.getDocumentByHash(fileHash)
|
||||||
|
|
||||||
if (existingDoc == null) {
|
if (existingDoc == null) {
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 🆕 发现新PDF文件: ${file.name}")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 🆕 发现新PDF文件: ${file.name}"
|
||||||
|
)
|
||||||
val thumbnailPath = generateThumbnail(context, file)
|
val thumbnailPath = generateThumbnail(context, file)
|
||||||
|
|
||||||
val metadata =
|
val metadata =
|
||||||
@ -81,11 +103,20 @@ class PdfScanner(
|
|||||||
metadataModificationDate = metadata?.modificationDate?.time
|
metadataModificationDate = metadata?.modificationDate?.time
|
||||||
)
|
)
|
||||||
pdfRepository.insertOrUpdateDocument(document)
|
pdfRepository.insertOrUpdateDocument(document)
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: ✅ 已保存到数据库: ${file.name}")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: ✅ 已保存到数据库: ${file.name}"
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 📋 文件已存在: ${file.name}")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 📋 文件已存在: ${file.name}"
|
||||||
|
)
|
||||||
if (existingDoc.filePath != file.absolutePath) {
|
if (existingDoc.filePath != file.absolutePath) {
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: 🔄 更新文件路径: ${existingDoc.filePath} -> ${file.absolutePath}")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: 🔄 更新文件路径: ${existingDoc.filePath} -> ${file.absolutePath}"
|
||||||
|
)
|
||||||
val updatedDoc = existingDoc.copy(
|
val updatedDoc = existingDoc.copy(
|
||||||
filePath = file.absolutePath,
|
filePath = file.absolutePath,
|
||||||
lastModified = file.lastModified()
|
lastModified = file.lastModified()
|
||||||
@ -103,14 +134,21 @@ class PdfScanner(
|
|||||||
docs.forEach { doc ->
|
docs.forEach { doc ->
|
||||||
LogUtil.logDebug(
|
LogUtil.logDebug(
|
||||||
"ocean",
|
"ocean",
|
||||||
"PdfScanner: 📖 ${doc.fileName} - ${doc.pageCount}页 - ${FileUtils.formatFileSize(doc.fileSize)} - ${doc.thumbnailPath}"
|
"PdfScanner: 📖 ${doc.fileName} - ${doc.pageCount}页 - ${
|
||||||
|
FileUtils.formatFileSize(
|
||||||
|
doc.fileSize
|
||||||
|
)
|
||||||
|
} - ${doc.thumbnailPath}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记扫描完成
|
// 标记扫描完成
|
||||||
ScanManager.markScanComplete(context)
|
ScanManager.markScanComplete(context)
|
||||||
val lastScanTime = ScanManager.getLastScanTime(context)
|
val lastScanTime = ScanManager.getLastScanTime(context)
|
||||||
LogUtil.logDebug("ocean", "PdfScanner: ✅ 扫描完成,记录时间: ${java.util.Date(lastScanTime)}")
|
LogUtil.logDebug(
|
||||||
|
"ocean",
|
||||||
|
"PdfScanner: ✅ 扫描完成,记录时间: ${java.util.Date(lastScanTime)}"
|
||||||
|
)
|
||||||
callback.invoke(true)
|
callback.invoke(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,12 +175,17 @@ class PdfScanner(
|
|||||||
|
|
||||||
private fun generateThumbnail(context: Context, pdfFile: File): String? {
|
private fun generateThumbnail(context: Context, pdfFile: File): String? {
|
||||||
return try {
|
return try {
|
||||||
val fileDescriptor = ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY)
|
val fileDescriptor =
|
||||||
|
ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY)
|
||||||
val pdfRenderer = PdfRenderer(fileDescriptor)
|
val pdfRenderer = PdfRenderer(fileDescriptor)
|
||||||
|
|
||||||
if (pdfRenderer.pageCount > 0) {
|
if (pdfRenderer.pageCount > 0) {
|
||||||
val page = pdfRenderer.openPage(0)
|
val page = pdfRenderer.openPage(0)
|
||||||
|
// 创建 Bitmap
|
||||||
val bitmap = createBitmap(page.width, page.height)
|
val bitmap = createBitmap(page.width, page.height)
|
||||||
|
val canvas = Canvas(bitmap)
|
||||||
|
canvas.drawColor(Color.WHITE) // 填充白色背景
|
||||||
|
|
||||||
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
|
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
|
||||||
page.close()
|
page.close()
|
||||||
|
|
||||||
@ -169,5 +212,4 @@ class PdfScanner(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
9
app/src/main/res/drawable/back_black.xml
Normal file
9
app/src/main/res/drawable/back_black.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="256dp"
|
||||||
|
android:height="256dp"
|
||||||
|
android:viewportWidth="1024"
|
||||||
|
android:viewportHeight="1024">
|
||||||
|
<path
|
||||||
|
android:pathData="M927.9,478.1 L168.9,478.1l308.7,-308.9c11.7,-11.7 11.4,-30.9 -0.6,-42.9 -12,-12 -31.2,-12.2 -42.9,-0.5L75.2,484.9c-2,1.7 -3.8,3.6 -5.3,5.7 -4,5.4 -6,11.8 -5.9,18.3 -0.1,7.8 2.7,15.6 8.6,21.4l361.6,361.7c11.7,11.7 30.9,11.4 42.9,-0.5 12,-12 12.2,-31.2 0.6,-42.9L168.4,539.5l759.4,0c16.5,0 29.9,-13.7 29.9,-30.7S944.4,478.1 927.9,478.1z"
|
||||||
|
android:fillColor="#2c2c2c"/>
|
||||||
|
</vector>
|
||||||
7
app/src/main/res/drawable/dr_item_img_frame.xml
Normal file
7
app/src/main/res/drawable/dr_item_img_frame.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<stroke android:color="@color/line_color"
|
||||||
|
android:width="1dp"/>
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
</shape>
|
||||||
BIN
app/src/main/res/font/poppins_medium.ttf
Normal file
BIN
app/src/main/res/font/poppins_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/poppins_regular.ttf
Normal file
BIN
app/src/main/res/font/poppins_regular.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/poppins_semibold.ttf
Normal file
BIN
app/src/main/res/font/poppins_semibold.ttf
Normal file
Binary file not shown.
@ -90,7 +90,7 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/pnLayout"
|
android:id="@+id/pnLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="58dp"
|
android:layout_height="64dp"
|
||||||
android:background="@drawable/dr_rounded_corner_top_bg_grey"
|
android:background="@drawable/dr_rounded_corner_top_bg_grey"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
@ -115,18 +115,20 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_medium"
|
||||||
android:text="@string/notice"
|
android:text="@string/notice"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:text="@string/permission_notice"
|
android:text="@string/permission_notice"
|
||||||
android:textColor="@color/black_60"
|
android:textColor="@color/black_60"
|
||||||
android:textSize="14sp" />
|
android:textSize="12sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@ -140,14 +142,14 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/dr_click_btn_bg"
|
android:background="@drawable/dr_click_btn_bg"
|
||||||
|
android:fontFamily="@font/poppins_semibold"
|
||||||
android:paddingStart="24dp"
|
android:paddingStart="24dp"
|
||||||
android:paddingTop="4dp"
|
android:paddingTop="4dp"
|
||||||
android:paddingEnd="24dp"
|
android:paddingEnd="24dp"
|
||||||
android:paddingBottom="4dp"
|
android:paddingBottom="4dp"
|
||||||
android:text="@string/go"
|
android:text="@string/go"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp" />
|
||||||
android:textStyle="bold" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@ -173,6 +175,7 @@
|
|||||||
android:id="@+id/home_tv"
|
android:id="@+id/home_tv"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:text="@string/home"
|
android:text="@string/home"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
@ -196,6 +199,7 @@
|
|||||||
android:id="@+id/recently_tv"
|
android:id="@+id/recently_tv"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:text="@string/recently"
|
android:text="@string/recently"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
@ -219,6 +223,7 @@
|
|||||||
android:id="@+id/favorite_tv"
|
android:id="@+id/favorite_tv"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:text="@string/favorite"
|
android:text="@string/favorite"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
@ -242,6 +247,7 @@
|
|||||||
android:id="@+id/tools_tv"
|
android:id="@+id/tools_tv"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:text="@string/tools"
|
android:text="@string/tools"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|||||||
44
app/src/main/res/layout/activity_pdf_view.xml
Normal file
44
app/src/main/res/layout/activity_pdf_view.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/backBtn"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/back_black" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/bg_color">
|
||||||
|
|
||||||
|
<com.github.barteksc.pdfviewer.PDFView
|
||||||
|
android:id="@+id/pdfview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -2,8 +2,8 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
|
||||||
android:background="@color/bg_color"
|
android:background="@color/bg_color"
|
||||||
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- App Logo -->
|
<!-- App Logo -->
|
||||||
@ -19,10 +19,10 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
|
android:fontFamily="@font/poppins_semibold"
|
||||||
android:text="@string/app_name"
|
android:text="@string/app_name"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp" />
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<!-- App Description -->
|
<!-- App Description -->
|
||||||
<TextView
|
<TextView
|
||||||
@ -31,6 +31,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:alpha="0.8"
|
android:alpha="0.8"
|
||||||
|
android:fontFamily="@font/poppins_medium"
|
||||||
android:text="@string/splash_desc"
|
android:text="@string/splash_desc"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|||||||
@ -14,11 +14,18 @@
|
|||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageView
|
<RelativeLayout
|
||||||
android:id="@+id/tvFileImg"
|
android:layout_width="56dp"
|
||||||
android:layout_width="54dp"
|
android:layout_height="56dp"
|
||||||
android:layout_height="54dp"
|
android:background="@drawable/dr_item_img_frame">
|
||||||
android:src="@mipmap/ic_launcher_round" />
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/tvFileImg"
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -32,12 +39,12 @@
|
|||||||
android:id="@+id/tvFileName"
|
android:id="@+id/tvFileName"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:maxLines="1"
|
||||||
android:text="@string/app_name"
|
android:text="@string/app_name"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold" />
|
android:fontFamily="@font/poppins_semibold"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -51,6 +58,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="2月27,2025"
|
android:text="2月27,2025"
|
||||||
|
android:fontFamily="@font/poppins_medium"
|
||||||
android:textColor="@color/black_60"
|
android:textColor="@color/black_60"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
@ -60,6 +68,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:text="8.1MB"
|
android:text="8.1MB"
|
||||||
|
android:fontFamily="@font/poppins_medium"
|
||||||
android:textColor="@color/black_60"
|
android:textColor="@color/black_60"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
|||||||
@ -40,17 +40,18 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:fontFamily="@font/poppins_semibold"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/permission_required"
|
android:text="@string/permission_required"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp" />
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/pr_desc"
|
android:id="@+id/pr_desc"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/permission_required_desc_1"
|
android:text="@string/permission_required_desc_1"
|
||||||
android:textColor="@color/black_80"
|
android:textColor="@color/black_80"
|
||||||
@ -76,6 +77,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:text="@string/permission_required_desc_2"
|
android:text="@string/permission_required_desc_2"
|
||||||
android:textColor="@color/black_80"
|
android:textColor="@color/black_80"
|
||||||
@ -105,10 +107,10 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_semibold"
|
||||||
android:text="@string/allow_access"
|
android:text="@string/allow_access"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp" />
|
||||||
android:textStyle="bold" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
android:text="@string/sort_by"
|
android:text="@string/sort_by"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold" />
|
android:fontFamily="@font/poppins_semibold"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -41,6 +41,7 @@
|
|||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="@string/created_date"
|
android:text="@string/created_date"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
@ -69,6 +70,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="@string/file_name"
|
android:text="@string/file_name"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
@ -101,6 +103,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:text="@string/file_size"
|
android:text="@string/file_size"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
@ -145,6 +148,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:text="@string/ascending"
|
android:text="@string/ascending"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
@ -177,6 +181,7 @@
|
|||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="@string/descending"
|
android:text="@string/descending"
|
||||||
|
android:fontFamily="@font/poppins_regular"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
@ -211,7 +216,7 @@
|
|||||||
android:text="@string/cancel"
|
android:text="@string/cancel"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/black"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold" />
|
android:fontFamily="@font/poppins_semibold" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -229,7 +234,7 @@
|
|||||||
android:text="@string/ok"
|
android:text="@string/ok"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold" />
|
android:fontFamily="@font/poppins_semibold" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@ -18,7 +18,9 @@
|
|||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingBottom="40dp" />
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
<string name="file_size">File Size</string>
|
<string name="file_size">File Size</string>
|
||||||
<string name="ascending">Ascending</string>
|
<string name="ascending">Ascending</string>
|
||||||
<string name="descending">Descending</string>
|
<string name="descending">Descending</string>
|
||||||
<string name="permission_denied">权限被拒绝</string>
|
<string name="permission_denied">Permission Denied</string>
|
||||||
<string name="pd_content_notice">Unable to access PDF file, please grant storage permission in settings</string>
|
<string name="pd_content_notice">Unable to access PDF file, please grant storage permission in settings</string>
|
||||||
|
<string name="file_not">File does not exist</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -1,6 +1,8 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
androidpdfviewer = "3.2.8"
|
||||||
appcompat = "1.7.1"
|
appcompat = "1.7.1"
|
||||||
agp = "8.10.1"
|
agp = "8.10.1"
|
||||||
|
glide = "5.0.4"
|
||||||
kotlin = "2.0.21"
|
kotlin = "2.0.21"
|
||||||
ksp = "2.0.21-1.0.27"
|
ksp = "2.0.21-1.0.27"
|
||||||
coreKtx = "1.17.0"
|
coreKtx = "1.17.0"
|
||||||
@ -10,6 +12,7 @@ espressoCore = "3.7.0"
|
|||||||
lifecycleRuntimeKtx = "2.9.2"
|
lifecycleRuntimeKtx = "2.9.2"
|
||||||
immersionbar = "3.2.2"
|
immersionbar = "3.2.2"
|
||||||
immersionbarKtx = "3.2.2"
|
immersionbarKtx = "3.2.2"
|
||||||
|
pdfboxAndroid = "2.0.27.0"
|
||||||
room_version = "2.7.2"
|
room_version = "2.7.2"
|
||||||
swiperefreshlayout = "1.1.0"
|
swiperefreshlayout = "1.1.0"
|
||||||
recyclerview = "1.4.0"
|
recyclerview = "1.4.0"
|
||||||
@ -17,11 +20,13 @@ protoliteWellKnownTypes = "18.0.1"
|
|||||||
material = "1.12.0"
|
material = "1.12.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
androidpdfviewer = { module = "com.github.marain87:AndroidPdfViewer", version.ref = "androidpdfviewer" }
|
||||||
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
|
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room_version" }
|
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room_version" }
|
||||||
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room_version" }
|
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room_version" }
|
||||||
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room_version" }
|
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room_version" }
|
||||||
|
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
@ -30,6 +35,7 @@ immersionbar = { group = "com.geyifeng.immersionbar", name = "immersionbar", ver
|
|||||||
immersionbar-ktx = { group = "com.geyifeng.immersionbar", name = "immersionbar-ktx", version.ref = "immersionbarKtx" }
|
immersionbar-ktx = { group = "com.geyifeng.immersionbar", name = "immersionbar-ktx", version.ref = "immersionbarKtx" }
|
||||||
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
|
androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
|
||||||
androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
|
androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
|
||||||
|
pdfbox-android = { module = "com.tom-roush:pdfbox-android", version.ref = "pdfboxAndroid" }
|
||||||
protolite-well-known-types = { group = "com.google.firebase", name = "protolite-well-known-types", version.ref = "protoliteWellKnownTypes" }
|
protolite-well-known-types = { group = "com.google.firebase", name = "protolite-well-known-types", version.ref = "protoliteWellKnownTypes" }
|
||||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ dependencyResolutionManagement {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven("https://jitpack.io")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user