拆分功能完成,包含所有功能。
This commit is contained in:
parent
df84891d91
commit
298585b602
@ -73,6 +73,12 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ui.act.SplitPdfResultActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:screenOrientation="portrait" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
|||||||
@ -22,12 +22,22 @@ import com.all.pdfreader.pro.app.ui.dialog.RenameDialogFragment
|
|||||||
import com.all.pdfreader.pro.app.util.FileUtils.toUnderscoreDateTime
|
import com.all.pdfreader.pro.app.util.FileUtils.toUnderscoreDateTime
|
||||||
import com.all.pdfreader.pro.app.util.PdfUtils
|
import com.all.pdfreader.pro.app.util.PdfUtils
|
||||||
import com.gyf.immersionbar.ImmersionBar
|
import com.gyf.immersionbar.ImmersionBar
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class SplitPdfActivity : BaseActivity() {
|
class SplitPdfActivity : BaseActivity() {
|
||||||
override val TAG: String = "SplitPdfActivity"
|
override val TAG: String = "SplitPdfActivity"
|
||||||
|
|
||||||
|
|
||||||
|
private var currentViewState: ViewState = ViewState.SPLIT_LIST
|
||||||
|
|
||||||
|
private enum class ViewState {
|
||||||
|
SPLIT_LIST, // 拆分页列表
|
||||||
|
SPLIT_SELECTED // 已选页面列表
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_PDF_PATH = "extra_pdf_path"
|
private const val EXTRA_PDF_PATH = "extra_pdf_path"
|
||||||
|
|
||||||
@ -110,8 +120,7 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
binding.continueNowBtn.setOnClickListener {
|
binding.continueNowBtn.setOnClickListener {
|
||||||
val selectedPages = splitList.filter { it.isSelected }.map { it.copy() }
|
val selectedPages = splitList.filter { it.isSelected }.map { it.copy() }
|
||||||
val name =
|
val name = getString(R.string.split) + "_" + System.currentTimeMillis().toUnderscoreDateTime()
|
||||||
getString(R.string.split) + "_" + System.currentTimeMillis().toUnderscoreDateTime()
|
|
||||||
val item = PdfSelectedPagesItem(filePath, name, selectedPages)
|
val item = PdfSelectedPagesItem(filePath, name, selectedPages)
|
||||||
selectedList.add(item)
|
selectedList.add(item)
|
||||||
selectedPdfAdapter.updateAdapter()
|
selectedPdfAdapter.updateAdapter()
|
||||||
@ -119,20 +128,28 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
updateViewState(true)
|
updateViewState(true)
|
||||||
}
|
}
|
||||||
binding.addBtn.setOnClickListener {
|
binding.addBtn.setOnClickListener {
|
||||||
//点击重新添加后,选中状态全部置为false,全选按钮置为false
|
binding.continueNowBtn.isEnabled = false//继续按钮不可点击
|
||||||
|
updateContinueNowBtnState(false)//重置继续按钮背景
|
||||||
adapter.setAllSelected(false)
|
adapter.setAllSelected(false)
|
||||||
updateSelectAllState(false)
|
updateSelectAllState(false)
|
||||||
updateViewState(false)
|
updateViewState(false)
|
||||||
}
|
}
|
||||||
binding.splitBtn.setOnClickListener {
|
binding.splitBtn.setOnClickListener {
|
||||||
|
//因为图片做的路径缓存方式,所以这里直接传入整个集合到result页处理
|
||||||
|
val intent = SplitPdfResultActivity.createIntent(this, ArrayList(selectedList))
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSplitData(file: File) {
|
private fun initSplitData(file: File) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
splitList.clear()
|
splitList.clear()
|
||||||
PdfUtils.clearPdfThumbsCache(this@SplitPdfActivity) // 先清理旧缓存
|
// 先切换到 IO 线程执行删除,等待完成
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
PdfUtils.clearPdfThumbsCache(this@SplitPdfActivity)
|
||||||
|
}
|
||||||
|
// 删除完成后,开始收集数据
|
||||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
var firstPageLoaded = false
|
var firstPageLoaded = false
|
||||||
PdfUtils.splitPdfToPageItemsFlow(this@SplitPdfActivity, file).collect { pageItem ->
|
PdfUtils.splitPdfToPageItemsFlow(this@SplitPdfActivity, file).collect { pageItem ->
|
||||||
@ -143,7 +160,7 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
splitList[pageItem.pageIndex] = pageItem
|
splitList[pageItem.pageIndex] = pageItem
|
||||||
adapter.updateItem(pageItem.pageIndex)
|
adapter.updateItem(pageItem.pageIndex)
|
||||||
}
|
}
|
||||||
if (!firstPageLoaded) {//有数据回来则隐藏loading,显示全选按钮
|
if (!firstPageLoaded) {
|
||||||
binding.loadingRoot.root.visibility = View.GONE
|
binding.loadingRoot.root.visibility = View.GONE
|
||||||
binding.selectAllBtn.visibility = View.VISIBLE
|
binding.selectAllBtn.visibility = View.VISIBLE
|
||||||
firstPageLoaded = true
|
firstPageLoaded = true
|
||||||
@ -176,10 +193,12 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
|
|
||||||
private fun updateViewState(b: Boolean) {
|
private fun updateViewState(b: Boolean) {
|
||||||
if (b) {
|
if (b) {
|
||||||
|
currentViewState = ViewState.SPLIT_SELECTED
|
||||||
binding.selectAllBtn.visibility = View.GONE//隐藏全选按钮
|
binding.selectAllBtn.visibility = View.GONE//隐藏全选按钮
|
||||||
binding.addBtn.visibility = View.VISIBLE//显示add按钮
|
binding.addBtn.visibility = View.VISIBLE//显示add按钮
|
||||||
binding.title.text = getString(R.string.split_pdf)//设置标题
|
binding.title.text = getString(R.string.split_pdf)//设置标题
|
||||||
} else {
|
} else {
|
||||||
|
currentViewState = ViewState.SPLIT_LIST
|
||||||
binding.selectAllBtn.visibility = View.VISIBLE
|
binding.selectAllBtn.visibility = View.VISIBLE
|
||||||
binding.addBtn.visibility = View.GONE
|
binding.addBtn.visibility = View.GONE
|
||||||
binding.title.text =
|
binding.title.text =
|
||||||
@ -221,15 +240,19 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
splitList.clear()
|
|
||||||
PdfUtils.clearPdfThumbsCache(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBackPressedCallback() {
|
private fun setupBackPressedCallback() {
|
||||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
if (isSelectedViewShow) {
|
if (!isSelectedViewShow) {//点击继续后,说明已经操过过了,不直接finish
|
||||||
//使用提示对话框
|
isEnabled = false
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
when (currentViewState) {
|
||||||
|
ViewState.SPLIT_SELECTED -> {
|
||||||
|
// 已选页面列表,提示是否退出
|
||||||
PromptDialogFragment(
|
PromptDialogFragment(
|
||||||
getString(R.string.exit_split),
|
getString(R.string.exit_split),
|
||||||
getString(R.string.confirm_discard_changes),
|
getString(R.string.confirm_discard_changes),
|
||||||
@ -238,9 +261,16 @@ class SplitPdfActivity : BaseActivity() {
|
|||||||
isEnabled = false
|
isEnabled = false
|
||||||
onBackPressedDispatcher.onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
}).show(supportFragmentManager, getString(R.string.exit_split))
|
}).show(supportFragmentManager, getString(R.string.exit_split))
|
||||||
} else {
|
}
|
||||||
isEnabled = false
|
|
||||||
onBackPressedDispatcher.onBackPressed()
|
ViewState.SPLIT_LIST -> {
|
||||||
|
// 拆分页列表,返回到已选页面列表
|
||||||
|
adapter.setAllSelected(false)//重置所有选中状态为false
|
||||||
|
updateSelectAllState(false)//重置选中按钮
|
||||||
|
binding.continueNowBtn.isEnabled = false//继续按钮不可点击
|
||||||
|
updateContinueNowBtnState(false)//重置继续按钮背景
|
||||||
|
updateViewState(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,11 +2,17 @@ package com.all.pdfreader.pro.app.ui.act
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.view.View
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.all.pdfreader.pro.app.PRApp
|
||||||
import com.all.pdfreader.pro.app.R
|
import com.all.pdfreader.pro.app.R
|
||||||
import com.all.pdfreader.pro.app.databinding.ActivityPdfSplitResultBinding
|
import com.all.pdfreader.pro.app.databinding.ActivityPdfSplitResultBinding
|
||||||
import com.all.pdfreader.pro.app.model.PdfPageItem
|
import com.all.pdfreader.pro.app.model.PdfPageItem
|
||||||
@ -14,9 +20,14 @@ import com.all.pdfreader.pro.app.model.PdfSelectedPagesItem
|
|||||||
import com.all.pdfreader.pro.app.model.PdfSplitResultItem
|
import com.all.pdfreader.pro.app.model.PdfSplitResultItem
|
||||||
import com.all.pdfreader.pro.app.ui.act.SplitPdfActivity
|
import com.all.pdfreader.pro.app.ui.act.SplitPdfActivity
|
||||||
import com.all.pdfreader.pro.app.ui.adapter.SplitPdfResultAdapter
|
import com.all.pdfreader.pro.app.ui.adapter.SplitPdfResultAdapter
|
||||||
|
import com.all.pdfreader.pro.app.ui.dialog.PromptDialogFragment
|
||||||
|
import com.all.pdfreader.pro.app.util.AppUtils
|
||||||
|
import com.all.pdfreader.pro.app.util.PdfScanner
|
||||||
import com.all.pdfreader.pro.app.util.PdfUtils
|
import com.all.pdfreader.pro.app.util.PdfUtils
|
||||||
import com.gyf.immersionbar.ImmersionBar
|
import com.gyf.immersionbar.ImmersionBar
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class SplitPdfResultActivity : BaseActivity() {
|
class SplitPdfResultActivity : BaseActivity() {
|
||||||
@ -26,11 +37,10 @@ class SplitPdfResultActivity : BaseActivity() {
|
|||||||
private const val EXTRA_SELECTED_LIST = "extra_selected_list"
|
private const val EXTRA_SELECTED_LIST = "extra_selected_list"
|
||||||
|
|
||||||
fun createIntent(
|
fun createIntent(
|
||||||
context: Context,
|
context: Context, list: ArrayList<PdfSelectedPagesItem>
|
||||||
selectedPageIndices: List<Int>
|
|
||||||
): Intent {
|
): Intent {
|
||||||
return Intent(context, SplitPdfResultActivity::class.java).apply {
|
return Intent(context, SplitPdfResultActivity::class.java).apply {
|
||||||
|
putParcelableArrayListExtra(EXTRA_SELECTED_LIST, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,15 +48,24 @@ class SplitPdfResultActivity : BaseActivity() {
|
|||||||
private lateinit var binding: ActivityPdfSplitResultBinding
|
private lateinit var binding: ActivityPdfSplitResultBinding
|
||||||
private lateinit var adapter: SplitPdfResultAdapter
|
private lateinit var adapter: SplitPdfResultAdapter
|
||||||
private var splitResultList: MutableList<PdfSplitResultItem> = mutableListOf()
|
private var splitResultList: MutableList<PdfSplitResultItem> = mutableListOf()
|
||||||
|
private lateinit var selectedList: ArrayList<PdfSelectedPagesItem>
|
||||||
|
private var isSplitting = false
|
||||||
|
private var exitDialog: PromptDialogFragment? = null
|
||||||
|
private val pdfRepository = getRepository()
|
||||||
|
private lateinit var pdfScanner: PdfScanner
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityPdfSplitResultBinding.inflate(layoutInflater)
|
binding = ActivityPdfSplitResultBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
setupBackPressedCallback()
|
||||||
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
|
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
|
||||||
.navigationBarColor(R.color.bg_color).init()
|
.navigationBarColor(R.color.bg_color).init()
|
||||||
|
selectedList = requireParcelableArrayList(EXTRA_SELECTED_LIST)
|
||||||
|
pdfScanner = PdfScanner(this, pdfRepository)
|
||||||
initView()
|
initView()
|
||||||
setupClick()
|
setupClick()
|
||||||
|
initData()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
@ -55,25 +74,80 @@ class SplitPdfResultActivity : BaseActivity() {
|
|||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startSplittingPDF(
|
private fun initData() {
|
||||||
inputFile: File, selectedPages: List<PdfPageItem>, outputDir: File, outputFileName: String
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
) {
|
val totalPages = selectedList.sumOf { it.pages.count { it.isSelected } }
|
||||||
lifecycleScope.launch {
|
var processedPages = 0
|
||||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
||||||
val resultFile = PdfUtils.exportSelectedPages(
|
withContext(Dispatchers.Main) {
|
||||||
|
isSplitting = true
|
||||||
|
binding.splittingLayout.visibility = View.VISIBLE
|
||||||
|
binding.progressBar.isIndeterminate = false
|
||||||
|
binding.progressBar.progress = 0
|
||||||
|
binding.progressBar.max = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
for (item in selectedList) {
|
||||||
|
val selectedPages = item.pages.filter { it.isSelected }
|
||||||
|
if (selectedPages.isEmpty()) continue
|
||||||
|
|
||||||
|
val inputFile = File(item.filePath)
|
||||||
|
val outputDir = File(
|
||||||
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS),
|
||||||
|
"PDFReaderPro/split"
|
||||||
|
).apply { if (!exists()) mkdirs() }
|
||||||
|
|
||||||
|
PdfUtils.exportSelectedPages(
|
||||||
inputFile = inputFile,
|
inputFile = inputFile,
|
||||||
selectedPages = selectedPages,
|
selectedPages = selectedPages,
|
||||||
outputDir = outputDir,
|
outputDir = outputDir,
|
||||||
outputFileName = outputFileName,
|
outputFileName = "${item.fileName}.pdf",
|
||||||
onProgress = { current, total ->
|
onProgress = { _, _ -> // 不需要单文件百分比
|
||||||
|
processedPages++// 每页处理完成就加一,多个 PDF 顺序处理时,总进度线性递增
|
||||||
})
|
val percent = (processedPages.toFloat() / totalPages * 100).toInt()
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
binding.progressTv.text = "$percent"
|
||||||
|
binding.progressBar.progress = percent
|
||||||
|
}
|
||||||
|
})?.let { resultFile ->
|
||||||
|
val thumbnails =
|
||||||
|
AppUtils.generateFastThumbnail(this@SplitPdfResultActivity, resultFile)
|
||||||
|
val result = PdfSplitResultItem(resultFile.absolutePath, thumbnails, false)
|
||||||
|
pdfScanner.addNewPdfToDatabase(result.filePath, result.thumbnailPath) {
|
||||||
|
splitResultList.add(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.splittingLayout.visibility = View.GONE
|
||||||
|
// 默认选中第一个
|
||||||
|
if (splitResultList.isNotEmpty() && splitResultList.none { it.isSelected }) {
|
||||||
|
splitResultList[0].isSelected = true
|
||||||
|
}
|
||||||
|
adapter.updateAdapter()
|
||||||
|
isSplitting = false//拆分结束
|
||||||
|
exitDialog?.dismissAllowingStateLoss()
|
||||||
|
exitDialog = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupClick() {
|
private fun setupClick() {
|
||||||
binding.backBtn.setOnClickListener {
|
binding.backBtn.setOnClickListener {
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
}
|
||||||
|
binding.shareBtn.setOnClickListener {
|
||||||
|
val selectedItem = adapter.getSelectedItem()
|
||||||
|
selectedItem?.let {
|
||||||
|
AppUtils.shareFile(this, File(selectedItem.filePath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.okBtn.setOnClickListener {
|
||||||
|
val selectedItem = adapter.getSelectedItem()
|
||||||
|
selectedItem?.let {
|
||||||
|
val intent = PdfViewActivity.createIntent(this, selectedItem.filePath)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,4 +156,42 @@ class SplitPdfResultActivity : BaseActivity() {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupBackPressedCallback() {
|
||||||
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
if (isSplitting) {
|
||||||
|
exitDialog = PromptDialogFragment(
|
||||||
|
getString(R.string.exit_split),
|
||||||
|
getString(R.string.confirm_discard_changes),
|
||||||
|
getString(R.string.discard),
|
||||||
|
onOkClick = {
|
||||||
|
isEnabled = false
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
})
|
||||||
|
exitDialog?.show(supportFragmentManager, getString(R.string.exit_split))
|
||||||
|
} else {
|
||||||
|
isEnabled = false
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用方法:读取必传参数,如果为 null 直接 finish
|
||||||
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
private inline fun <reified T : Parcelable> requireParcelableArrayList(key: String): ArrayList<T> {
|
||||||
|
val result: ArrayList<T>? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
intent.getParcelableArrayListExtra(key, T::class.java)
|
||||||
|
} else {
|
||||||
|
intent.getParcelableArrayListExtra(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.isNullOrEmpty()) {
|
||||||
|
showToast(getString(R.string.pdf_loading_failed))
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
return result ?: arrayListOf()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -43,6 +43,20 @@ class SplitPdfResultAdapter(
|
|||||||
} else {
|
} else {
|
||||||
holder.binding.selectIv.visibility = View.INVISIBLE
|
holder.binding.selectIv.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
|
holder.binding.root.setOnClickListener {
|
||||||
|
val oldSelectedIndex = list.indexOfFirst { it.isSelected }
|
||||||
|
val newSelectedIndex = holder.bindingAdapterPosition
|
||||||
|
if (oldSelectedIndex != newSelectedIndex && newSelectedIndex != RecyclerView.NO_POSITION) {
|
||||||
|
// 取消之前选中
|
||||||
|
if (oldSelectedIndex >= 0) {
|
||||||
|
list[oldSelectedIndex].isSelected = false
|
||||||
|
notifyItemChanged(oldSelectedIndex)
|
||||||
|
}
|
||||||
|
// 选中当前
|
||||||
|
list[newSelectedIndex].isSelected = true
|
||||||
|
notifyItemChanged(newSelectedIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = list.size
|
override fun getItemCount(): Int = list.size
|
||||||
@ -52,7 +66,7 @@ class SplitPdfResultAdapter(
|
|||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItem(position: Int) = notifyItemChanged(position)
|
fun getSelectedItem(): PdfSplitResultItem? {
|
||||||
|
return list.firstOrNull { it.isSelected }
|
||||||
fun removeItem(position: Int) = notifyItemRemoved(position)
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,8 +70,7 @@ class PdfScanner(
|
|||||||
val newThumbnail = generateFastThumbnail(context, file)
|
val newThumbnail = generateFastThumbnail(context, file)
|
||||||
if (newThumbnail != null && doc.thumbnailPath != newThumbnail) {
|
if (newThumbnail != null && doc.thumbnailPath != newThumbnail) {
|
||||||
pdfRepository.updateThumbnailPath(
|
pdfRepository.updateThumbnailPath(
|
||||||
doc.filePath,
|
doc.filePath, newThumbnail
|
||||||
newThumbnail
|
|
||||||
)
|
)
|
||||||
LogUtil.logDebug(TAG, "✅ 缩略图已更新")
|
LogUtil.logDebug(TAG, "✅ 缩略图已更新")
|
||||||
}
|
}
|
||||||
@ -136,8 +135,7 @@ class PdfScanner(
|
|||||||
val newThumbnail = generateFastThumbnail(context, file)
|
val newThumbnail = generateFastThumbnail(context, file)
|
||||||
if (newThumbnail != null && document.thumbnailPath != newThumbnail) {
|
if (newThumbnail != null && document.thumbnailPath != newThumbnail) {
|
||||||
pdfRepository.updateThumbnailPath(
|
pdfRepository.updateThumbnailPath(
|
||||||
document.filePath,
|
document.filePath, newThumbnail
|
||||||
newThumbnail
|
|
||||||
)
|
)
|
||||||
LogUtil.logDebug(TAG, "✅ 缩略图已更新")
|
LogUtil.logDebug(TAG, "✅ 缩略图已更新")
|
||||||
}
|
}
|
||||||
@ -162,8 +160,7 @@ class PdfScanner(
|
|||||||
val currentIsPassword = isPdfEncrypted(file)
|
val currentIsPassword = isPdfEncrypted(file)
|
||||||
if (existingDoc.isPassword != currentIsPassword) {
|
if (existingDoc.isPassword != currentIsPassword) {
|
||||||
LogUtil.logDebug(TAG, "✅ 密码状态需要更新")
|
LogUtil.logDebug(TAG, "✅ 密码状态需要更新")
|
||||||
updatedDoc =
|
updatedDoc = updatedDoc.copy(isPassword = currentIsPassword)
|
||||||
updatedDoc.copy(isPassword = currentIsPassword)
|
|
||||||
needUpdate = true
|
needUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,8 +177,7 @@ class PdfScanner(
|
|||||||
val newThumbnail = generateFastThumbnail(context, file)
|
val newThumbnail = generateFastThumbnail(context, file)
|
||||||
if (newThumbnail != null && existingDoc.thumbnailPath != newThumbnail) {
|
if (newThumbnail != null && existingDoc.thumbnailPath != newThumbnail) {
|
||||||
pdfRepository.updateThumbnailPath(
|
pdfRepository.updateThumbnailPath(
|
||||||
existingDoc.filePath,
|
existingDoc.filePath, newThumbnail
|
||||||
newThumbnail
|
|
||||||
)
|
)
|
||||||
LogUtil.logDebug(TAG, "✅ 缩略图已更新")
|
LogUtil.logDebug(TAG, "✅ 缩略图已更新")
|
||||||
}
|
}
|
||||||
@ -194,7 +190,9 @@ class PdfScanner(
|
|||||||
val file = File(doc.filePath)
|
val file = File(doc.filePath)
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
// 文件不存在 → 删除数据库记录
|
// 文件不存在 → 删除数据库记录
|
||||||
LogUtil.logDebug(TAG, "最终过滤:文件不存在 -> ${doc.fileName}, 删除记录")
|
LogUtil.logDebug(
|
||||||
|
TAG, "最终过滤:文件不存在 -> ${doc.fileName}, 删除记录"
|
||||||
|
)
|
||||||
pdfRepository.deleteDocument(doc.filePath)
|
pdfRepository.deleteDocument(doc.filePath)
|
||||||
} else {
|
} else {
|
||||||
LogUtil.logDebug(
|
LogUtil.logDebug(
|
||||||
@ -240,16 +238,62 @@ class PdfScanner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldScan(): Boolean {
|
/**
|
||||||
return ScanManager.shouldScan(context)
|
* 添加单个pdf文件到数据库
|
||||||
|
*/
|
||||||
|
suspend fun addNewPdfToDatabase(
|
||||||
|
pathFile: String,
|
||||||
|
thumbnailPath: String?,
|
||||||
|
callback: (Boolean) -> Unit = {}
|
||||||
|
) {
|
||||||
|
val file = File(pathFile)
|
||||||
|
if (!file.exists() || !FileUtils.isPdfFile(file)) {
|
||||||
|
LogUtil.logDebug(TAG, "文件不存在或不是PDF: $pathFile")
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
callback.invoke(false)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLastScanTime(): Long {
|
try {
|
||||||
return ScanManager.getLastScanTime(context)
|
withContext(Dispatchers.IO) {
|
||||||
|
val existingDoc = pdfRepository.getDocumentByPath(file.absolutePath)
|
||||||
|
if (existingDoc == null) {
|
||||||
|
val isPassword = isPdfEncrypted(file)
|
||||||
|
val metadata = PdfMetadataExtractor.extractMetadata(file.absolutePath)
|
||||||
|
|
||||||
|
val document = PdfDocumentEntity(
|
||||||
|
filePath = file.absolutePath,
|
||||||
|
fileName = file.name,
|
||||||
|
fileSize = file.length(),
|
||||||
|
lastModified = file.lastModified(),
|
||||||
|
pageCount = metadata?.pageCount ?: 0,
|
||||||
|
thumbnailPath = thumbnailPath,
|
||||||
|
metadataTitle = metadata?.title,
|
||||||
|
metadataAuthor = metadata?.author,
|
||||||
|
metadataSubject = metadata?.subject,
|
||||||
|
metadataKeywords = metadata?.keywords,
|
||||||
|
metadataCreationDate = metadata?.creationDate?.time,
|
||||||
|
metadataModificationDate = metadata?.modificationDate?.time,
|
||||||
|
isPassword = isPassword
|
||||||
|
)
|
||||||
|
|
||||||
|
pdfRepository.insertOrUpdateDocument(document)
|
||||||
|
LogUtil.logDebug(TAG, "✅ 新PDF已保存到数据库: ${file.name}")
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
callback.invoke(true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "数据库有已有相同的文件")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "❌ 添加新PDF出错: ${e.message}", e)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
callback.invoke(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHoursSinceLastScan(): Long {
|
|
||||||
val lastScan = getLastScanTime()
|
|
||||||
return TimeUnit.MILLISECONDS.toHours(System.currentTimeMillis() - lastScan)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -133,5 +133,4 @@ object PdfUtils {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,57 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp" />
|
android:layout_height="0dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/splittingLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/progressTv"
|
||||||
|
style="@style/TextViewFont_PopSemiBold"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="0"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="32sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextViewFont_PopSemiBold"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="%"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextViewFont_PopMedium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/splitting"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_margin="32dp"
|
||||||
|
android:indeterminate="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/statusLayout"
|
android:id="@+id/statusLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -122,7 +173,7 @@
|
|||||||
style="@style/TextViewFont_PopSemiBold"
|
style="@style/TextViewFont_PopSemiBold"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/ok"
|
android:text="@string/open"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@ -15,10 +15,11 @@
|
|||||||
<string name="permission_notice">Permission is required to access files</string>
|
<string name="permission_notice">Permission is required to access files</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="ok">OK</string>
|
<string name="ok">OK</string>
|
||||||
|
<string name="open">Open</string>
|
||||||
<string name="sort_by">Sort by</string>
|
<string name="sort_by">Sort by</string>
|
||||||
<string name="created_date">Created Date</string>
|
<string name="created_date">Created Date</string>
|
||||||
<string name="path">Path</string>
|
<string name="path">Path</string>
|
||||||
<string name="path_details">Path %1$s</string>
|
<string name="path_details">Path: %1$s</string>
|
||||||
<string name="file_name">File Name</string>
|
<string name="file_name">File Name</string>
|
||||||
<string name="file_size">File Size</string>
|
<string name="file_size">File Size</string>
|
||||||
<string name="ascending">Ascending</string>
|
<string name="ascending">Ascending</string>
|
||||||
@ -133,4 +134,5 @@
|
|||||||
<string name="congratulations">Congratulations</string>
|
<string name="congratulations">Congratulations</string>
|
||||||
<string name="file_created_success">Your file has been successfully created</string>
|
<string name="file_created_success">Your file has been successfully created</string>
|
||||||
<string name="please_select_page">Please select at least one page</string>
|
<string name="please_select_page">Please select at least one page</string>
|
||||||
|
<string name="splitting">Splitting…</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue
Block a user