添加pdf拆分二级功能界面。

This commit is contained in:
ocean 2025-09-23 18:33:25 +08:00
parent 06a2720547
commit df84891d91
25 changed files with 969 additions and 85 deletions

View File

@ -1,10 +1,14 @@
package com.all.pdfreader.pro.app.model package com.all.pdfreader.pro.app.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
/** /**
* 拆分pdf展示用的每页信息 * 拆分pdf展示用的每页信息
*/ */
@Parcelize
data class PdfPageItem( data class PdfPageItem(
val pageIndex: Int, val pageIndex: Int,
var previewFilePath: String?, // 缓存文件路径 var previewFilePath: String?, // 缓存文件路径
var isSelected: Boolean var isSelected: Boolean
) ) : Parcelable

View File

@ -0,0 +1,31 @@
package com.all.pdfreader.pro.app.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
/**
* 拆分pdf被选中使用的结构
*/
@Parcelize
data class PdfSelectedPagesItem(
val filePath: String,
var fileName: String, // 文件名
val pages: List<PdfPageItem> // 所有页的数据
): Parcelable {
/**
* 获取已选中的页面列表
*/
fun selectedPages(): List<PdfPageItem> =
pages.filter { it.isSelected }.sortedBy { it.pageIndex }
/**
* 获取已选中的页码字符串例如 "1,2,3,4,6"
*/
fun selectedPageNumbersString(): String =
selectedPages().joinToString(",") { (it.pageIndex + 1).toString() }
/**
* 获取第一个图片没有返回空字符串
*/
fun getFirstThumbPath(): String = pages.first().previewFilePath ?: ""
}

View File

@ -0,0 +1,7 @@
package com.all.pdfreader.pro.app.model
data class PdfSplitResultItem(
val filePath: String,
val thumbnailPath: String? = null,
var isSelected: Boolean
)

View File

@ -2,5 +2,6 @@ package com.all.pdfreader.pro.app.model
enum class RenameType { enum class RenameType {
FILE, // 修改文件名 FILE, // 修改文件名
BOOKMARK // 修改书签名 BOOKMARK, // 修改书签名
NAME // 修改集合的item名称
} }

View File

@ -4,14 +4,22 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View 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.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.all.pdfreader.pro.app.R import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.ActivityPdfSplitBinding import com.all.pdfreader.pro.app.databinding.ActivityPdfSplitBinding
import com.all.pdfreader.pro.app.model.PdfPageItem import com.all.pdfreader.pro.app.model.PdfPageItem
import com.all.pdfreader.pro.app.model.PdfSelectedPagesItem
import com.all.pdfreader.pro.app.model.RenameType
import com.all.pdfreader.pro.app.ui.adapter.SplitPdfAdapter import com.all.pdfreader.pro.app.ui.adapter.SplitPdfAdapter
import com.all.pdfreader.pro.app.ui.adapter.SplitSelectedPdfAdapter
import com.all.pdfreader.pro.app.ui.dialog.PromptDialogFragment
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.PdfUtils import com.all.pdfreader.pro.app.util.PdfUtils
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -33,14 +41,19 @@ class SplitPdfActivity : BaseActivity() {
private lateinit var binding: ActivityPdfSplitBinding private lateinit var binding: ActivityPdfSplitBinding
private lateinit var adapter: SplitPdfAdapter private lateinit var adapter: SplitPdfAdapter
private var splitList: MutableList<PdfPageItem> = mutableListOf() private var splitList: MutableList<PdfPageItem> = mutableListOf()
private var selectedList: MutableList<PdfSelectedPagesItem> = mutableListOf()
private lateinit var selectedPdfAdapter: SplitSelectedPdfAdapter
private var isSelectedViewShow = false//用于返回的时候是否提示(点击了继续按钮就会产生提示)
private lateinit var filePath: String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityPdfSplitBinding.inflate(layoutInflater) binding = ActivityPdfSplitBinding.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.white).init() .navigationBarColor(R.color.bg_color).init()
val filePath = intent.getStringExtra(EXTRA_PDF_PATH) filePath = intent.getStringExtra(EXTRA_PDF_PATH)
?: throw IllegalArgumentException("PDF file hash is required") ?: throw IllegalArgumentException("PDF file hash is required")
if (filePath.isEmpty()) { if (filePath.isEmpty()) {
showToast(getString(R.string.file_not)) showToast(getString(R.string.file_not))
@ -52,40 +65,77 @@ class SplitPdfActivity : BaseActivity() {
} }
private fun initView() { private fun initView() {
binding.continueNowBtn.isEnabled = false
binding.title.text = getString(R.string.selected_page, 0) binding.title.text = getString(R.string.selected_page, 0)
binding.selectAllBtn.visibility = View.GONE binding.selectAllBtn.visibility = View.GONE//初始隐藏全选按钮
binding.loadingRoot.root.visibility = View.VISIBLE binding.addBtn.visibility = View.GONE//初始隐藏add按钮
binding.loadingRoot.root.visibility = View.VISIBLE//初始显示loading
binding.splitRv.layoutManager = GridLayoutManager(this, 2) binding.splitRv.layoutManager = GridLayoutManager(this, 2)
adapter = SplitPdfAdapter(splitList) { item, pos -> adapter = SplitPdfAdapter(splitList) { item, pos ->
item.isSelected = !item.isSelected item.isSelected = !item.isSelected
adapter.setItemSelected(pos, item.isSelected) adapter.setItemSelected(pos, item.isSelected)
binding.title.text = getString(R.string.selected_page, adapter.getSelPages()) binding.title.text = getString(R.string.selected_page, adapter.getSelPages())
// 只有存在选中的item则为true
val anySelected = splitList.any { it.isSelected }
binding.continueNowBtn.isEnabled = anySelected
updateContinueNowBtnState(anySelected)
} }
binding.splitRv.adapter = adapter binding.splitRv.adapter = adapter
selectedPdfAdapter = SplitSelectedPdfAdapter(selectedList, onEditClick = { item, pos ->
RenameDialogFragment(
RenameType.NAME, null, item.fileName, onOkClickString = { string ->
selectedList[pos].fileName = string
selectedPdfAdapter.updateItem(pos)
}).show(supportFragmentManager, "BookmarksDialogFragment")
}, onDeleteClick = { item, pos ->
selectedList.remove(item)
selectedPdfAdapter.removeItem(pos)
updateSplitBtnState(selectedList.isNotEmpty())
})
binding.splitSelectRv.layoutManager = LinearLayoutManager(this)
binding.splitSelectRv.adapter = selectedPdfAdapter
} }
private fun setupClick() { private fun setupClick() {
binding.backBtn.setOnClickListener { finish() } binding.backBtn.setOnClickListener { onBackPressedDispatcher.onBackPressed() }
binding.selectAllBtn.setOnClickListener { binding.selectAllBtn.setOnClickListener {
val selectAll = splitList.any { !it.isSelected } val selectAll = splitList.any { !it.isSelected }//如果列表里有一页没选中 → 返回 true
adapter.setAllSelected(selectAll) adapter.setAllSelected(selectAll)
binding.title.text = getString(R.string.selected_page, adapter.getSelPages()) binding.title.text = getString(R.string.selected_page, adapter.getSelPages())
binding.continueNowBtn.isEnabled = selectAll
updateSelectAllState(selectAll)
updateContinueNowBtnState(selectAll)
}
binding.continueNowBtn.setOnClickListener {
val selectedPages = splitList.filter { it.isSelected }.map { it.copy() }
val name =
getString(R.string.split) + "_" + System.currentTimeMillis().toUnderscoreDateTime()
val item = PdfSelectedPagesItem(filePath, name, selectedPages)
selectedList.add(item)
selectedPdfAdapter.updateAdapter()
isSelectedViewShow = true
updateViewState(true)
}
binding.addBtn.setOnClickListener {
//点击重新添加后选中状态全部置为false全选按钮置为false
adapter.setAllSelected(false)
updateSelectAllState(false)
updateViewState(false)
}
binding.splitBtn.setOnClickListener {
if (selectAll) {
binding.selectAll.setBackgroundResource(R.drawable.dr_circular_sel_on_bg)
} else {
binding.selectAll.setBackgroundResource(R.drawable.dr_circular_sel_off_bg)
}
} }
} }
private fun initSplitData(file: File) { private fun initSplitData(file: File) {
lifecycleScope.launch { lifecycleScope.launch {
splitList.clear()
PdfUtils.clearPdfThumbsCache(this@SplitPdfActivity) // 先清理旧缓存 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 ->
logDebug("pageItem flow ->$pageItem")
if (splitList.size <= pageItem.pageIndex) { if (splitList.size <= pageItem.pageIndex) {
splitList.add(pageItem) splitList.add(pageItem)
adapter.notifyItemInserted(splitList.size - 1) adapter.notifyItemInserted(splitList.size - 1)
@ -93,20 +143,106 @@ class SplitPdfActivity : BaseActivity() {
splitList[pageItem.pageIndex] = pageItem splitList[pageItem.pageIndex] = pageItem
adapter.updateItem(pageItem.pageIndex) adapter.updateItem(pageItem.pageIndex)
} }
if (!firstPageLoaded) { if (!firstPageLoaded) {//有数据回来则隐藏loading显示全选按钮
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
} }
} }
binding.loadingRoot.root.visibility = View.GONE
} }
} }
} }
private fun updateSelectAllState(b: Boolean) {
binding.selectAll.setBackgroundResource(
if (b) R.drawable.dr_circular_sel_on_bg
else R.drawable.dr_circular_sel_off_bg
)
}
private fun updateContinueNowBtnState(b: Boolean) {
binding.continueNowBtn.setBackgroundResource(
if (b) R.drawable.dr_click_btn_bg
else R.drawable.dr_btn_not_clickable_bg
)
}
private fun updateSplitBtnState(b: Boolean) {
binding.splitBtn.setBackgroundResource(
if (b) R.drawable.dr_click_btn_bg
else R.drawable.dr_btn_not_clickable_bg
)
}
private fun updateViewState(b: Boolean) {
if (b) {
binding.selectAllBtn.visibility = View.GONE//隐藏全选按钮
binding.addBtn.visibility = View.VISIBLE//显示add按钮
binding.title.text = getString(R.string.split_pdf)//设置标题
} else {
binding.selectAllBtn.visibility = View.VISIBLE
binding.addBtn.visibility = View.GONE
binding.title.text =
getString(R.string.selected_page, adapter.getSelPages())//重新设置标题为选中了多少个
}
updateViewStateWithAnimation(b)
updateSplitBtnState(selectedList.isNotEmpty())
}
private fun updateViewStateWithAnimation(showSelectedView: Boolean) {
if (showSelectedView) {
// 切换到已选页面列表
binding.splitListLayout.animate().translationY(-50f).alpha(0f).setDuration(200)
.withEndAction {
binding.splitListLayout.visibility = View.GONE
binding.splitListLayout.translationY = 0f
}.start()
binding.splitSelectLayout.alpha = 0f
binding.splitSelectLayout.translationY = 50f
binding.splitSelectLayout.visibility = View.VISIBLE
binding.splitSelectLayout.animate().translationY(0f).alpha(1f).setDuration(200).start()
} else {
// 切回拆分页列表
binding.splitSelectLayout.animate().translationY(50f).alpha(0f).setDuration(200)
.withEndAction {
binding.splitSelectLayout.visibility = View.GONE
binding.splitSelectLayout.translationY = 0f
}.start()
binding.splitListLayout.alpha = 0f
binding.splitListLayout.translationY = -50f
binding.splitListLayout.visibility = View.VISIBLE
binding.splitListLayout.animate().translationY(0f).alpha(1f).setDuration(200).start()
}
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
splitList.clear() splitList.clear()
PdfUtils.clearPdfThumbsCache(this) PdfUtils.clearPdfThumbsCache(this)
} }
private fun setupBackPressedCallback() {
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (isSelectedViewShow) {
//使用提示对话框
PromptDialogFragment(
getString(R.string.exit_split),
getString(R.string.confirm_discard_changes),
getString(R.string.discard),
onOkClick = {
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}).show(supportFragmentManager, getString(R.string.exit_split))
} else {
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
}
})
}
} }

View File

@ -0,0 +1,85 @@
package com.all.pdfreader.pro.app.ui.act
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.ActivityPdfSplitResultBinding
import com.all.pdfreader.pro.app.model.PdfPageItem
import com.all.pdfreader.pro.app.model.PdfSelectedPagesItem
import com.all.pdfreader.pro.app.model.PdfSplitResultItem
import com.all.pdfreader.pro.app.ui.act.SplitPdfActivity
import com.all.pdfreader.pro.app.ui.adapter.SplitPdfResultAdapter
import com.all.pdfreader.pro.app.util.PdfUtils
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.launch
import java.io.File
class SplitPdfResultActivity : BaseActivity() {
override val TAG: String = "SplitPdfResultActivity"
companion object {
private const val EXTRA_SELECTED_LIST = "extra_selected_list"
fun createIntent(
context: Context,
selectedPageIndices: List<Int>
): Intent {
return Intent(context, SplitPdfResultActivity::class.java).apply {
}
}
}
private lateinit var binding: ActivityPdfSplitResultBinding
private lateinit var adapter: SplitPdfResultAdapter
private var splitResultList: MutableList<PdfSplitResultItem> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPdfSplitResultBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
.navigationBarColor(R.color.bg_color).init()
initView()
setupClick()
}
private fun initView() {
adapter = SplitPdfResultAdapter(splitResultList)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
}
private fun startSplittingPDF(
inputFile: File, selectedPages: List<PdfPageItem>, outputDir: File, outputFileName: String
) {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
val resultFile = PdfUtils.exportSelectedPages(
inputFile = inputFile,
selectedPages = selectedPages,
outputDir = outputDir,
outputFileName = outputFileName,
onProgress = { current, total ->
})
}
}
}
private fun setupClick() {
binding.backBtn.setOnClickListener {
finish()
}
}
override fun onDestroy() {
super.onDestroy()
}
}

View File

@ -51,10 +51,12 @@ class SplitPdfAdapter(
holder.binding.apply { holder.binding.apply {
//更新文字图片与选中状态 //更新文字图片与选中状态
pageNumberTv.text = "${item.pageIndex + 1}" pageNumberTv.text = "${item.pageIndex + 1}"
Glide.with(holder.binding.root) if (item.previewFilePath != null) {
.load(File(item.previewFilePath ?: "")) Glide.with(holder.binding.root)
.transform(CenterCrop(), RoundedCorners(8.dpToPx(holder.binding.root.context))) .load(File(item.previewFilePath ?: ""))
.into(image) .transform(CenterCrop(), RoundedCorners(8.dpToPx(holder.binding.root.context)))
.into(image)
}
bindSelection(item, holder) bindSelection(item, holder)
} }
holder.binding.root.setOnClickListener { holder.binding.root.setOnClickListener {
@ -74,7 +76,7 @@ class SplitPdfAdapter(
private fun bindSelection(item: PdfPageItem, holder: PdfViewHolder) { private fun bindSelection(item: PdfPageItem, holder: PdfViewHolder) {
val b = holder.binding val b = holder.binding
val selRes = val selRes =
if (item.isSelected) R.drawable.dr_circular_sel_on_bg else R.drawable.dr_circular_sel_off_bg if (item.isSelected) R.drawable.dr_item_page_img_sel_on_bg else R.drawable.dr_item_page_img_sel_off_bg
b.selIv.setBackgroundResource(selRes) b.selIv.setBackgroundResource(selRes)
val bgRes = if (item.isSelected) R.drawable.dr_sel_on_frame else R.drawable.dr_sel_off_frame val bgRes = if (item.isSelected) R.drawable.dr_sel_on_frame else R.drawable.dr_sel_off_frame

View File

@ -0,0 +1,58 @@
package com.all.pdfreader.pro.app.ui.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.AdapterSplitSelectedResultItemBinding
import com.all.pdfreader.pro.app.model.PdfSplitResultItem
import com.all.pdfreader.pro.app.util.AppUtils.dpToPx
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import java.io.File
class SplitPdfResultAdapter(
private val list: MutableList<PdfSplitResultItem>
) : RecyclerView.Adapter<SplitPdfResultAdapter.PdfViewHolder>() {
inner class PdfViewHolder(val binding: AdapterSplitSelectedResultItemBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = PdfViewHolder(
AdapterSplitSelectedResultItemBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
)
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: PdfViewHolder, position: Int) {
val item = list[position]
if (item.thumbnailPath != null) {
Glide.with(holder.binding.root).load(File(item.thumbnailPath))
.transform(CenterCrop(), RoundedCorners(8.dpToPx(holder.binding.root.context)))
.into(holder.binding.image)
}
holder.binding.nameTv.text = File(item.filePath).name
holder.binding.pathTv.text =
holder.binding.root.context.getString(R.string.path_details, item.filePath)
if (item.isSelected) {
holder.binding.selectIv.visibility = View.VISIBLE
} else {
holder.binding.selectIv.visibility = View.INVISIBLE
}
}
override fun getItemCount(): Int = list.size
@SuppressLint("NotifyDataSetChanged")
fun updateAdapter() {
notifyDataSetChanged()
}
fun updateItem(position: Int) = notifyItemChanged(position)
fun removeItem(position: Int) = notifyItemRemoved(position)
}

View File

@ -0,0 +1,61 @@
package com.all.pdfreader.pro.app.ui.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.all.pdfreader.pro.app.databinding.AdapterSplitSelectedPageItemBinding
import com.all.pdfreader.pro.app.model.PdfSelectedPagesItem
import com.all.pdfreader.pro.app.util.AppUtils.dpToPx
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import java.io.File
class SplitSelectedPdfAdapter(
private val list: MutableList<PdfSelectedPagesItem>,
private val onEditClick: (PdfSelectedPagesItem, Int) -> Unit,
private val onDeleteClick: (PdfSelectedPagesItem, Int) -> Unit
) : RecyclerView.Adapter<SplitSelectedPdfAdapter.PdfViewHolder>() {
inner class PdfViewHolder(val binding: AdapterSplitSelectedPageItemBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = PdfViewHolder(
AdapterSplitSelectedPageItemBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
)
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: PdfViewHolder, position: Int) {
val item = list[position]
holder.binding.tvPages.text = item.selectedPageNumbersString()
val thumbPath = item.getFirstThumbPath()
if (thumbPath.isNotEmpty()) {
Glide.with(holder.binding.root).load(File(thumbPath))
.transform(CenterCrop(), RoundedCorners(8.dpToPx(holder.binding.root.context)))
.into(holder.binding.tvFileImg)
}
holder.binding.tvFileName.text = item.fileName
holder.binding.editTitleBtn.setOnClickListener {
val pos = holder.bindingAdapterPosition
onEditClick(item, pos)
}
holder.binding.deleteBtn.setOnClickListener {
val pos = holder.bindingAdapterPosition
onDeleteClick(item, pos)
}
}
override fun getItemCount(): Int = list.size
@SuppressLint("NotifyDataSetChanged")
fun updateAdapter() {
notifyDataSetChanged()
}
fun updateItem(position: Int) = notifyItemChanged(position)
fun removeItem(position: Int) = notifyItemRemoved(position)
}

View File

@ -1,7 +1,6 @@
package com.all.pdfreader.pro.app.ui.dialog package com.all.pdfreader.pro.app.ui.dialog
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -125,10 +124,10 @@ class BookmarksDialogFragment(
dialogAddBookMarks() dialogAddBookMarks()
} }
binding.deleteALLPageBtn.setOnClickListener { binding.deleteALLPageBtn.setOnClickListener {
DeleteDialogFragment( PromptDialogFragment(
getString(R.string.delete_bookmarks_title), getString(R.string.delete_bookmarks_title),
getString(R.string.delete_bookmarks_desc), getString(R.string.delete_bookmarks_desc),
onDeleteClick = { onOkClick = {
viewModel.deleteAllBookmark(pdfDocument.filePath) viewModel.deleteAllBookmark(pdfDocument.filePath)
adapter.removeAllItems() adapter.removeAllItems()
bookmarks = emptyList() bookmarks = emptyList()

View File

@ -1,7 +1,6 @@
package com.all.pdfreader.pro.app.ui.dialog package com.all.pdfreader.pro.app.ui.dialog
import android.net.Uri import android.net.Uri
import android.nfc.Tag
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -115,10 +114,10 @@ class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment()
dismiss() dismiss()
} }
binding.deleteFileBtn.setOnClickListener { binding.deleteFileBtn.setOnClickListener {
DeleteDialogFragment( PromptDialogFragment(
getString(R.string.delete_file_title), getString(R.string.delete_file_title),
getString(R.string.delete_file_desc), getString(R.string.delete_file_desc),
onDeleteClick = { onOkClick = {
viewModel.deleteFile(pdfDocument.filePath) viewModel.deleteFile(pdfDocument.filePath)
}).show(parentFragmentManager, "deleteFile") }).show(parentFragmentManager, "deleteFile")
dismiss() dismiss()
@ -179,11 +178,11 @@ class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment()
dismiss() dismiss()
} }
binding.removeRecentBtn.setOnClickListener { binding.removeRecentBtn.setOnClickListener {
DeleteDialogFragment( PromptDialogFragment(
getString(R.string.remove_dialog_title), getString(R.string.remove_dialog_title),
getString(R.string.remove_dialog_desc), getString(R.string.remove_dialog_desc),
getString(R.string.remove), getString(R.string.remove),
onDeleteClick = { onOkClick = {
viewModel.removeRecent(pdfDocument.filePath) viewModel.removeRecent(pdfDocument.filePath)
}).show(parentFragmentManager, "removeRecent") }).show(parentFragmentManager, "removeRecent")
dismiss() dismiss()

View File

@ -11,11 +11,12 @@ import androidx.fragment.app.DialogFragment
import com.all.pdfreader.pro.app.R import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.DialogDeleteBinding import com.all.pdfreader.pro.app.databinding.DialogDeleteBinding
class DeleteDialogFragment( class PromptDialogFragment(
private val title: String, private val title: String,
private val desc: String, private val desc: String,
private val okBtnText: String? = null, private val okBtnText: String? = null,
private val onDeleteClick: () -> Unit private val onOkClick: () -> Unit,
private val onCancelClick: () -> Unit = {}
) : DialogFragment() { ) : DialogFragment() {
private lateinit var binding: DialogDeleteBinding private lateinit var binding: DialogDeleteBinding
@ -54,10 +55,11 @@ class DeleteDialogFragment(
private fun setupOnClick() { private fun setupOnClick() {
binding.okBtn.setOnClickListener { binding.okBtn.setOnClickListener {
onDeleteClick() onOkClick()
dismiss() dismiss()
} }
binding.cancelBtn.setOnClickListener { binding.cancelBtn.setOnClickListener {
onCancelClick()
dismiss() dismiss()
} }
} }

View File

@ -23,7 +23,9 @@ import java.io.File
class RenameDialogFragment( class RenameDialogFragment(
private val type: RenameType, private val type: RenameType,
private val bookmark: BookmarkEntity? = null, private val bookmark: BookmarkEntity? = null,
private val onOkClick: (BookmarkEntity) -> Unit= {} private val name: String? = null,
private val onOkClick: (BookmarkEntity) -> Unit = {},
private val onOkClickString: (String) -> Unit = {}
) : DialogFragment() { ) : DialogFragment() {
private lateinit var binding: DialogRenameFileBinding private lateinit var binding: DialogRenameFileBinding
@ -71,6 +73,15 @@ class RenameDialogFragment(
dismiss() dismiss()
} }
} }
RenameType.NAME -> {
name?.let {
initView(it)
setupOnClick(it, it, null)
}?:run {
dismiss()
}
}
} }
} }
@ -104,6 +115,14 @@ class RenameDialogFragment(
dismiss() dismiss()
} }
} }
RenameType.NAME -> {
val text = binding.etName.text.toString()
if (validateEnter(text, oldName, filePath)) {
onOkClickString(text)
dismiss()
}
}
} }
} }
@ -161,6 +180,17 @@ class RenameDialogFragment(
return false return false
} }
} }
RenameType.NAME -> {
if (name.length > 50) {
binding.tilName.error = getString(R.string.name_too_long)
return false
}
if (name == oldName) {
binding.tilName.error = getString(R.string.name_not_changed)
return false
}
}
} }
// 禁止开头/结尾空格 // 禁止开头/结尾空格

View File

@ -5,38 +5,28 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.pdf.PdfRenderer
import android.net.Uri import android.net.Uri
import android.os.Bundle
import android.os.CancellationSignal
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.print.PageRange
import android.print.PrintAttributes import android.print.PrintAttributes
import android.print.PrintDocumentAdapter
import android.print.PrintDocumentInfo
import android.print.PrintManager import android.print.PrintManager
import android.print.pdf.PrintedPdfDocument
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.EditText import android.widget.EditText
import android.widget.Toast import android.widget.Toast
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import com.all.pdfreader.pro.app.R
import java.io.File
import java.io.FileOutputStream
import androidx.core.graphics.createBitmap import androidx.core.graphics.createBitmap
import androidx.print.PrintHelper import androidx.print.PrintHelper
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.model.PrintResult import com.all.pdfreader.pro.app.model.PrintResult
import com.all.pdfreader.pro.app.ui.adapter.PrintPdfAdapter import com.all.pdfreader.pro.app.ui.adapter.PrintPdfAdapter
import com.shockwave.pdfium.PdfDocument import com.shockwave.pdfium.PdfDocument
import com.shockwave.pdfium.PdfPasswordException import com.shockwave.pdfium.PdfPasswordException
import com.shockwave.pdfium.PdfiumCore import com.shockwave.pdfium.PdfiumCore
import com.tom_roush.pdfbox.pdmodel.PDDocument
import com.tom_roush.pdfbox.pdmodel.common.PDPageLabelRange import com.tom_roush.pdfbox.pdmodel.common.PDPageLabelRange
import java.io.File
import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
object AppUtils { object AppUtils {

View File

@ -326,7 +326,10 @@ object FileUtils {
return sdf.format(Date(this)) return sdf.format(Date(this))
} }
fun Long.toUnderscoreDateTime(): String {
val sdf = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH)
return sdf.format(Date(this))
}
data class FileInfo( data class FileInfo(
val name: String, val size: Long, val uri: Uri val name: String, val size: Long, val uri: Uri
) )

View File

@ -2,8 +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.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.util.Log
import androidx.core.graphics.createBitmap import androidx.core.graphics.createBitmap
import com.all.pdfreader.pro.app.model.PdfPageItem import com.all.pdfreader.pro.app.model.PdfPageItem
import com.shockwave.pdfium.PdfiumCore import com.shockwave.pdfium.PdfiumCore
@ -26,7 +26,8 @@ object PdfUtils {
fun clearPdfThumbsCache(context: Context) { fun clearPdfThumbsCache(context: Context) {
val cacheDir = File(context.cacheDir, child) val cacheDir = File(context.cacheDir, child)
if (cacheDir.exists()) { if (cacheDir.exists()) {
cacheDir.listFiles()?.forEach { it.delete() } val ss = cacheDir.deleteRecursively() // Kotlin 提供的递归删除方法
Log.d("ocean", "clearPdfThumbsCache->$ss")
} }
} }
@ -66,13 +67,10 @@ object PdfUtils {
val targetHeight = (height * scale).toInt() val targetHeight = (height * scale).toInt()
val bitmap = createBitmap(thumbWidth, targetHeight, Bitmap.Config.RGB_565) val bitmap = createBitmap(thumbWidth, targetHeight, Bitmap.Config.RGB_565)
val canvas = Canvas(bitmap) pdfiumCore.renderPageBitmap(pdfDocument, bitmap, i, 0, 0, thumbWidth, targetHeight)
canvas.scale(scale, scale)
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, i, 0, 0, width, height)
// 保存为压缩 JPEG // 保存为压缩 JPEG
val outFile = File(cacheDir, "page_$i.jpg") val outFile = File(cacheDir, inputFile.name + "_page_$i.jpg")
FileOutputStream(outFile).use { fos -> FileOutputStream(outFile).use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos) bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos)
} }
@ -89,36 +87,45 @@ object PdfUtils {
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
/** /**
* 获取 PDF 总页数 * 导出选中的 PDF 页到一个新的 PDF 文件
*/ *
fun getPdfPageCount(inputFile: File): Int { * 使用 PDFBox PDDocument 导出原 PDF 中选中的页支持进度回调
PDDocument.load(inputFile).use { return it.numberOfPages } * 避免直接使用缩略图生成 PDF以保持原 PDF 的矢量质量
} *
* @param inputFile PDF 文件
/** * @param selectedPages 选中的页对象列表每个对象包含 pageIndex
* 导出用户勾选的页生成新的 PDF * @param outputDir 输出目录如果不存在会自动创建
* @param inputFile PDF 文件 * @param outputFileName 输出文件名例如 "selected.pdf"
* @param selectedPages 用户选择的页列表 * @param onProgress 可选回调当前处理进度 (current , total )
* @param outputDir 输出目录外部存储可访问目录 * @return 新生成的 PDF 文件失败返回 null
* @param outputFileName 输出文件名
*/ */
suspend fun exportSelectedPages( suspend fun exportSelectedPages(
inputFile: File, selectedPages: List<PdfPageItem>, outputDir: File, outputFileName: String inputFile: File,
selectedPages: List<PdfPageItem>,
outputDir: File,
outputFileName: String,
onProgress: ((current: Int, total: Int) -> Unit)? = null
): File? = withContext(Dispatchers.IO) { ): File? = withContext(Dispatchers.IO) {
// 如果没有选中的页,直接返回 null
if (selectedPages.isEmpty()) return@withContext null if (selectedPages.isEmpty()) return@withContext null
if (!outputDir.exists()) outputDir.mkdirs()
if (!outputDir.exists()) outputDir.mkdirs() // 确保目录存在
val outputFile = File(outputDir, outputFileName) val outputFile = File(outputDir, outputFileName)
try { try {
PDDocument.load(inputFile).use { document -> PDDocument.load(inputFile).use { document ->
val newDocument = PDDocument() PDDocument().use { newDocument ->
selectedPages.sortedBy { it.pageIndex }.forEach { pageItem -> // 按页索引排序,保证顺序正确
val page = document.getPage(pageItem.pageIndex) val sortedPages = selectedPages.sortedBy { it.pageIndex }
newDocument.addPage(page) val total = sortedPages.size//总数
sortedPages.forEachIndexed { index, pageItem ->
// 导入原文档的页面到新文档
newDocument.importPage(document.getPage(pageItem.pageIndex))
// 回调进度
onProgress?.invoke(index + 1, total)
}
// 保存新 PDF 文件
newDocument.save(outputFile)
} }
newDocument.save(outputFile)
newDocument.close()
} }
outputFile outputFile
} catch (e: Exception) { } catch (e: Exception) {
@ -126,4 +133,5 @@ object PdfUtils {
null null
} }
} }
} }

View File

@ -2,6 +2,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">
<corners android:radius="8dp"/> <corners android:radius="8dp"/>
<solid android:color="@color/grey"/> <solid android:color="@color/placeholder_bg_color"/>
</shape> </shape>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 底部的虚线 -->
<item
android:gravity="bottom"
android:height="2dp">
<shape android:shape="line">
<stroke
android:width="1dp"
android:color="@color/line_color"
android:dashWidth="6dp"
android:dashGap="3dp" />
</shape>
</item>
</layer-list>

View File

@ -62,6 +62,25 @@
android:src="@drawable/gou_white" /> android:src="@drawable/gou_white" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/addBtn"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center">
<ImageView
android:id="@+id/addAll"
android:layout_width="24dp"
android:layout_height="24dp"
android:background="@drawable/dr_circular_sel_on_bg"
android:padding="2dp"
android:src="@drawable/add_icon_white" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<include <include
@ -70,13 +89,16 @@
android:visibility="gone" /> android:visibility="gone" />
<RelativeLayout <RelativeLayout
android:id="@+id/splitListLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:visibility="visible">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/splitRv" android:id="@+id/splitRv"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_above="@+id/continue_now_btn"
android:layout_margin="8dp" android:layout_margin="8dp"
android:overScrollMode="never" android:overScrollMode="never"
android:scrollbars="none" android:scrollbars="none"
@ -86,11 +108,14 @@
tools:listitem="@layout/adapter_split_page_item" /> tools:listitem="@layout/adapter_split_page_item" />
<LinearLayout <LinearLayout
android:id="@+id/allow_access_btn" android:id="@+id/continue_now_btn"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_margin="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:background="@drawable/dr_btn_not_clickable_bg" android:background="@drawable/dr_btn_not_clickable_bg"
android:gravity="center"> android:gravity="center">
@ -103,4 +128,43 @@
android:textSize="16sp" /> android:textSize="16sp" />
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/splitSelectLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/splitSelectRv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/splitBtn"
android:layout_margin="8dp"
android:overScrollMode="never"
android:scrollbars="none"
tools:itemCount="3"
tools:listitem="@layout/adapter_split_selected_page_item" />
<LinearLayout
android:id="@+id/splitBtn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:background="@drawable/dr_btn_not_clickable_bg"
android:gravity="center">
<TextView
style="@style/TextViewFont_PopSemiBold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/split_pdf"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_color"
android:orientation="vertical">
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="0dp" />
<LinearLayout
android:id="@+id/statusLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
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="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginTop="16dp"
android:background="@drawable/dr_circular_sel_on_bg"
android:src="@drawable/gou_white" />
<TextView
style="@style/TextViewFont_PopMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/congratulations"
android:textColor="@color/black"
android:textSize="20sp" />
<TextView
style="@style/TextViewFont_PopMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="@string/file_created_success"
android:textColor="@color/black_60"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_margin="16dp"
android:background="@color/line_color" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_margin="16dp"
tools:itemCount="3"
tools:listitem="@layout/adapter_split_selected_result_item" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
<LinearLayout
android:id="@+id/shareBtn"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:background="@drawable/dr_cancel_btn_bg"
android:gravity="center">
<TextView
style="@style/TextViewFont_PopSemiBold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/share_file"
android:textColor="@color/black_60"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/okBtn"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:background="@drawable/dr_click_btn_bg"
android:gravity="center">
<TextView
android:id="@+id/okBtnTv"
style="@style/TextViewFont_PopSemiBold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ok"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -19,11 +19,23 @@
android:layout_height="56dp" android:layout_height="56dp"
android:background="@drawable/dr_item_img_frame"> android:background="@drawable/dr_item_img_frame">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/dr_placeholder_bg"
android:gravity="center">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/file_document" />
</LinearLayout>
<ImageView <ImageView
android:id="@+id/tvFileImg" android:id="@+id/tvFileImg"
android:layout_width="56dp" android:layout_width="56dp"
android:layout_height="56dp" android:layout_height="56dp" />
android:src="@mipmap/ic_launcher_round" />
<LinearLayout <LinearLayout
android:visibility="gone" android:visibility="gone"

View File

@ -6,7 +6,7 @@
<RelativeLayout <RelativeLayout
android:id="@+id/itemBgLayout" android:id="@+id/itemBgLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="230dp" android:layout_height="220dp"
android:layout_margin="8dp" android:layout_margin="8dp"
android:background="@drawable/dr_sel_off_frame" android:background="@drawable/dr_sel_off_frame"
android:gravity="center" android:gravity="center"
@ -28,8 +28,7 @@
<ImageView <ImageView
android:id="@+id/image" android:id="@+id/image"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent" />
android:scaleType="centerCrop" />
<TextView <TextView
android:id="@+id/pageNumberTv" android:id="@+id/pageNumberTv"

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingTop="8dp"
tools:ignore="RtlSymmetry">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/dr_item_img_frame">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/dr_placeholder_bg"
android:gravity="center">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/file_document" />
</LinearLayout>
<ImageView
android:id="@+id/tvFileImg"
android:layout_width="56dp"
android:layout_height="56dp" />
</RelativeLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:id="@+id/editTitleBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="@+id/tvFileName"
style="@style/TextViewFont_PopMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@color/icon_color"
android:textSize="16sp" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="4dp"
android:layout_marginBottom="4dp"
android:src="@drawable/edit_icon" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="2dp"
android:background="@drawable/underline_dashed" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
style="@style/TextViewFont_PopRegular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/pages"
android:textColor="@color/black_60"
android:textSize="14sp" />
<TextView
android:id="@+id/tvPages"
style="@style/TextViewFont_PopRegular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:ellipsize="end"
android:maxLines="1"
android:text="0"
android:textColor="@color/black_60"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/deleteBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/delete_cha_icon" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/line_color" />
</LinearLayout>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingTop="8dp"
tools:ignore="RtlSymmetry">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/dr_item_img_frame">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/dr_placeholder_bg"
android:gravity="center">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/file_document" />
</LinearLayout>
<ImageView
android:id="@+id/image"
android:layout_width="56dp"
android:layout_height="56dp" />
</RelativeLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/nameTv"
style="@style/TextViewFont_PopMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@color/icon_color"
android:textSize="16sp" />
<TextView
android:id="@+id/pathTv"
style="@style/TextViewFont_PopRegular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/path_details"
android:textColor="@color/black_60"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/selectBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center">
<ImageView
android:id="@+id/selectIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/gou" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@color/line_color" />
</LinearLayout>

View File

@ -18,6 +18,7 @@
<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="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>
@ -120,8 +121,16 @@
<string name="bookmark_loading">Loading bookmarks, please try again later</string> <string name="bookmark_loading">Loading bookmarks, please try again later</string>
<string name="no_files_yet">no files yet</string> <string name="no_files_yet">no files yet</string>
<string name="split_pdf">Split PDF</string> <string name="split_pdf">Split PDF</string>
<string name="split">Split</string>
<string name="merge_pdf">Merge PDF</string> <string name="merge_pdf">Merge PDF</string>
<string name="selected_page">%1$d Selected</string> <string name="selected_page">%1$d Selected</string>
<string name="loading">Loading</string> <string name="loading">Loading</string>
<string name="continue_now">Continue Now</string> <string name="continue_now">Continue Now</string>
<string name="exit_split">Exit Split</string>
<string name="confirm_discard_changes">Are you sure you want to exit and discard changes?</string>
<string name="discard">Discard</string>
<string name="pages">Pages:</string>
<string name="congratulations">Congratulations</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>
</resources> </resources>