Commit d040b8f7 authored by wanglei's avatar wanglei

...深拷贝处理

parent 39eda934
......@@ -53,6 +53,41 @@
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".ui.pdf.PdfActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".ui.pdf.PdfMergeActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".ui.pdf.PdfSelectActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".ui.pdf.PdfSplitActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".ui.pdf.PdfLoadingActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
......
......@@ -27,6 +27,7 @@ object AdmobHelper {
const val native_limit_click = "native_limit_click"
//是否展示多语言
val showLanPage = "showLanPage"
......
......@@ -14,6 +14,12 @@ object ConstObject {
const val MIME_TYPE_APK = "application/vnd.android.package-archive"
const val MIME_TYPE_ZIP = "application/zip"
const val DO_SPLIT_PDF = "do_split_pdf"
const val DO_SAVE_PDF = "do_save_pdf"
const val DO_MERGE_PDF = "do_merge_pdf"
const val DO_LOCK_PDF = "do_lock_pdf"
const val DO_UNLOCK_PDF = "do_unlock_pdf"
var ifAgreePrivacy = false
get() {
return AppPreferences.getInstance().getBoolean("ifAgreePrivacy", field)
......@@ -32,4 +38,13 @@ object ConstObject {
AppPreferences.getInstance().put("haveSaveDemo", value, true)
}
var haveGuideGesture = false
get() {
return AppPreferences.getInstance().getBoolean("haveGuideGesture", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("haveGuideGesture", value, true)
}
}
\ No newline at end of file
......@@ -21,5 +21,17 @@ data class DocumentBean(
const val TYPE_WORD = "type_word"
const val TYPE_EXCEL = "type_excel"
const val TYPE_PPT = "type_ppt"
const val TYPE_FAVORITE = "type_favorite"
fun deepCopy(item: DocumentBean): DocumentBean {
return DocumentBean(item.path, item.uri, item.type, item.isBookmarked).apply {
this.uiType = item.uiType
this.isSelect = item.isSelect
this.state = item.state
this.password = item.password
this.lastViewTime = item.lastViewTime
this.isSelect = item.isAd
}
}
}
}
package com.base.pdfoneread.bean
import android.graphics.drawable.Drawable
data class PdfPageBean(
val pageIndex: Int = 0,
var pageDrawable: Drawable? = null
) {
var isSelect: Boolean = false
}
\ No newline at end of file
......@@ -9,6 +9,7 @@ import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_ALL
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_PDF
......@@ -16,12 +17,17 @@ import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfoneread.databinding.ActivityDocumentBinding
import com.base.pdfoneread.ui.BaseActivity
import com.base.pdfoneread.ui.views.DialogCallBack
import com.base.pdfoneread.ui.views.DocumentDialog.showDocumentHomeMoreDialog
import com.base.pdfoneread.ui.views.PdfDialog.showPdfHomeMoreDialog
import com.base.pdfoneread.utils.BarUtils
import com.base.pdfoneread.utils.PdfBoxUtils.checkPdfEncryption
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class DocumentActivity : BaseActivity<ActivityDocumentBinding>() {
class DocumentActivity : BaseActivity<ActivityDocumentBinding>(), DialogCallBack {
var type: String = ""
......@@ -55,6 +61,21 @@ class DocumentActivity : BaseActivity<ActivityDocumentBinding>() {
binding.tvTittle.text = "$size Selected"
binding.ivAllSelector.isSelected = size == adapter?.items?.size
}
adapter?.itemClick = { item: DocumentBean ->
if (item.type == TYPE_PDF) {
showPdfHomeMoreDialog(item, this)
} else {
showDocumentHomeMoreDialog(item, this)
}
}
adapter?.moreAction = { item: DocumentBean ->
if (item.type == TYPE_PDF) {
showPdfHomeMoreDialog(item, this)
} else {
showDocumentHomeMoreDialog(item, this)
}
}
binding.rv.adapter = adapter
}
......@@ -173,11 +194,13 @@ class DocumentActivity : BaseActivity<ActivityDocumentBinding>() {
}
if (list.isEmpty()) {
binding.swipeRefreshLayout.isRefreshing = true
initData()
} else {
binding.llEmpty.visibility = View.GONE
adapter?.submitList(getRvAdList(list))
}
if (isRefreshing.get()) {
initData()
}
}
......@@ -204,4 +227,35 @@ class DocumentActivity : BaseActivity<ActivityDocumentBinding>() {
}
//region DialogCallBack
override fun renameDocumentBean(file: File, newName: String) {
kotlin.runCatching {
val newFile = File(file.parentFile, newName)
val result = file.renameTo(newFile)
if (result) {
val renameItem = adapter?.items?.find { it.path == file.absolutePath }
if (renameItem != null) {
renameItem.path = newFile.absolutePath
adapter?.notifyDataSetChanged()
} else {
initData()
}
}
}
}
override fun deleteDocument(item: DocumentBean) {
val flag = File(item.path).delete()
if (flag) {
adapter?.remove(item)
}
}
override fun changePdfLock(item: DocumentBean) {
val pdf = adapter?.items?.find { it.path == item.path }
pdf?.state = checkPdfEncryption(item.path)
adapter?.notifyDataSetChanged()
}
//endregion
}
\ No newline at end of file
......@@ -49,7 +49,7 @@ class DocumentAdapter(
if (item.state == 0) {
binding.ivIcon.setImageResource(R.mipmap.rv_pdf)
} else {
binding.ivIcon.setImageResource(R.mipmap.pdf_s)
binding.ivIcon.setImageResource(R.mipmap.rv_pdf_s)
}
}
......
......@@ -19,8 +19,10 @@ import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfoneread.bean.DocumentBean.Companion.deepCopy
import com.base.pdfoneread.bean.MediaBean
import com.base.pdfoneread.utils.AssetUtils.readByteArrayFromAsset
import com.base.pdfoneread.utils.LogEx
import com.base.pdfoneread.utils.PdfBoxUtils.checkPdfEncryption
import com.base.pdfoneread.utils.SpStringUtils
import com.base.pdfoneread.utils.SpStringUtils.BOOKMARK_KEY
......@@ -29,7 +31,9 @@ import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
var isRefreshing: AtomicBoolean = AtomicBoolean(false)
/**
* 全局数据数据
......@@ -49,6 +53,7 @@ var GlobalExcelList = CopyOnWriteArrayList<DocumentBean>()
var GlobalPptList = CopyOnWriteArrayList<DocumentBean>()
fun cleanGlobalData() {
isRefreshing.compareAndSet(false, true)
GlobalPdfList.clear()
GlobalWordList.clear()
GlobalExcelList.clear()
......@@ -153,20 +158,21 @@ fun getAllDocument(context: Context): MutableList<DocumentBean> {
when (documentBean.type) {
TYPE_PDF -> {
context.pdfCheck(documentBean)
GlobalPdfList.add(documentBean)
GlobalPdfList.add(deepCopy(documentBean))
}
TYPE_WORD -> {
GlobalWordList.add(documentBean)
GlobalWordList.add(deepCopy(documentBean))
}
TYPE_EXCEL -> {
GlobalExcelList.add(documentBean)
GlobalExcelList.add(deepCopy(documentBean))
}
TYPE_PPT -> {
GlobalPptList.add(documentBean)
GlobalPptList.add(deepCopy(documentBean))
}
}
......@@ -195,6 +201,7 @@ fun getAllDocument(context: Context): MutableList<DocumentBean> {
new.add(0, pdfDemo)
GlobalPdfList.add(0, pdfDemo)
}
isRefreshing.compareAndSet(true, false)
return new
}
......@@ -223,16 +230,16 @@ fun getPdfDocument(context: Context): MutableList<DocumentBean> {
)
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
val demoDocumentBean = DocumentBean(it.path, uri = it.uri, type = TYPE_PDF)
context.pdfCheck(demoDocumentBean)
GlobalPdfList.add(demoDocumentBean)
demoDocumentBean
val documentBean = DocumentBean(it.path, uri = it.uri, type = TYPE_PDF)
context.pdfCheck(documentBean)
GlobalPdfList.add(deepCopy(documentBean))
documentBean
}
val new = documentList.toMutableList()
val pdfDemo = getPdfDemo(context)
if (File(pdfDemo.path).exists()) {
new.add(0, pdfDemo)
GlobalPdfList.add(0, pdfDemo)
GlobalPdfList.add(0, deepCopy(pdfDemo))
}
return new
}
......@@ -250,14 +257,14 @@ fun getWordDocument(context: Context): MutableList<DocumentBean> {
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
val document = DocumentBean(it.path, uri = it.uri, type = TYPE_WORD)
GlobalWordList.add(document)
GlobalWordList.add(deepCopy(document))
document
}
val new = documentList.toMutableList()
val wordDemo = getWordDemo(context)
if (File(wordDemo.path).exists()) {
new.add(0, wordDemo)
GlobalWordList.add(0, wordDemo)
GlobalWordList.add(0, deepCopy(wordDemo))
}
return new
}
......@@ -276,14 +283,14 @@ fun getExcelDocument(context: Context): MutableList<DocumentBean> {
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
val document = DocumentBean(it.path, uri = it.uri, type = TYPE_EXCEL)
GlobalExcelList.add(document)
GlobalExcelList.add(deepCopy(document))
document
}
val new = documentList.toMutableList()
val excelDemo = getExcelDemo(context)
if (File(excelDemo.path).exists()) {
new.add(0, excelDemo)
GlobalExcelList.add(0, excelDemo)
GlobalExcelList.add(0, deepCopy(excelDemo))
}
return new
}
......@@ -301,18 +308,19 @@ fun getPptDocument(context: Context): MutableList<DocumentBean> {
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
val document = DocumentBean(it.path, uri = it.uri, type = TYPE_PPT)
GlobalPptList.add(document)
GlobalPptList.add(deepCopy(document))
document
}
val new = documentList.toMutableList()
val pptDemo = getPPtDemo(context)
if (File(pptDemo.path).exists()) {
new.add(0, pptDemo)
GlobalPptList.add(0, pptDemo)
GlobalPptList.add(0, deepCopy(pptDemo))
}
return new
}
fun recentFilter(recentList: List<String>, documentBean: DocumentBean) {
val findLastTime = recentList.filter { it.contains(documentBean.path) }.map {
it.split("_/_")[1].toLong()
......@@ -349,10 +357,9 @@ fun saveBookmarkChange(addRemove: Boolean, path: String) {
}
}
fun getRvAdList(list: List<DocumentBean>): List<DocumentBean> {
val flag = AdmobHelper.isShowRvNativeAd()
if (flag) {
if (flag && list.isNotEmpty()) {
val arrayList = arrayListOf<DocumentBean>()
arrayList.addAll(list)
arrayList.add(1, DocumentBean().apply { isAd = true })
......
......@@ -6,9 +6,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.databinding.FragmentRecentBinding
import com.base.pdfoneread.ui.document.DocumentAdapter
import com.base.pdfoneread.ui.document.getAllDocument
import com.base.pdfoneread.ui.document.getGlobalAllList
import com.base.pdfoneread.ui.document.getRvAdList
import com.base.pdfoneread.ui.document.recentFilter
import com.base.pdfoneread.utils.SpStringUtils
import com.base.pdfoneread.utils.SpStringUtils.LAST_VIEW_KEY
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
......@@ -34,15 +40,44 @@ class RecentFragment() : Fragment() {
super.onViewCreated(view, savedInstanceState)
adapter = DocumentAdapter(requireActivity())
adapter = DocumentAdapter(requireActivity())
binding.rv.adapter = adapter
binding.swipeRefreshLayout.setOnRefreshListener {
initData()
}
initPreData()
}
private fun initPreData() = lifecycleScope.launch(Dispatchers.Main) {
adapter?.submitList(getGlobalAllList())
private fun initPreData() = lifecycleScope.launch(Dispatchers.IO) {
val recentList = SpStringUtils.getSpStringList(LAST_VIEW_KEY)
val allList = getGlobalAllList()
allList.forEach { recentFilter(recentList, it) }
val recent = allList.filter { it.lastViewTime != 0L }.sortedByDescending { it.lastViewTime }
val subList = getRvAdList(recent)
runOnUI(subList)
}
companion object {
private fun initData() = lifecycleScope.launch(Dispatchers.IO) {
val recentList = SpStringUtils.getSpStringList(LAST_VIEW_KEY)
val allList = getAllDocument(requireContext())
allList.forEach { recentFilter(recentList, it) }
val recent = allList.filter { it.lastViewTime != 0L }.sortedByDescending { it.lastViewTime }
val subList = getRvAdList(recent)
runOnUI(subList)
}
private fun runOnUI(list: List<DocumentBean>) {
lifecycleScope.launch(Dispatchers.Main) {
if (list.isEmpty()) {
binding.llEmpty.visibility = View.VISIBLE
adapter?.submitList(listOf())
} else {
binding.llEmpty.visibility = View.GONE
adapter?.submitList(list)
}
binding.swipeRefreshLayout.isRefreshing = false
}
}
}
\ No newline at end of file
This diff is collapsed.
package com.base.pdfoneread.ui.pdf
import android.content.Intent
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.artifex.mupdfdemo.MuPDFCore
import com.base.pdfoneread.ads.AdmobHelper
import com.base.pdfoneread.ads.admob.AdmobInterstitialUtils
import com.base.pdfoneread.bean.ConstObject.DO_MERGE_PDF
import com.base.pdfoneread.bean.ConstObject.DO_SAVE_PDF
import com.base.pdfoneread.bean.ConstObject.DO_SPLIT_PDF
import com.base.pdfoneread.databinding.ActivityPdfLoadingBinding
import com.base.pdfoneread.ui.BaseActivity
import com.base.pdfoneread.utils.LogEx
import com.base.pdfoneread.utils.ToastUtils.toast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.io.File
import kotlin.random.Random
class PdfLoadingActivity : BaseActivity<ActivityPdfLoadingBinding>() {
private val TAG = "PdfLoadingActivity"
private var doWhat = ""
private var srcPath: String = ""
private var newPath: String = ""
private var pwd: String? = null
private var splitIndex: List<Int> = listOf()
private lateinit var pdfViewModel: PdfViewModel
override val binding: ActivityPdfLoadingBinding by lazy {
ActivityPdfLoadingBinding.inflate(layoutInflater)
}
private var isFinishBoolean: Boolean = false
private var progressFinishAction: (() -> Unit)? = null
var resultFile: File? = null
override fun onResume() {
super.onResume()
// updateAppLanguage(MyApplication.pdfLoadingLanguage) {
// MyApplication.pdfLoadingLanguage = it
// }
}
private fun progressFinishAd(next: () -> Unit) {
if (AdmobHelper.canCommonShowAd()) {
AdmobInterstitialUtils.showInterstitialAd(this) {
next.invoke()
}
} else {
next.invoke()
}
}
override fun initView() {
// if (checkNeedRecreate(MyApplication.pdfLoadingLanguage)) {
// return
// }
pdfViewModel = ViewModelProvider(this)[PdfViewModel::class.java]
initSpPa()
pdfViewModel.password = pwd
when (doWhat) {
DO_SPLIT_PDF -> {
progressFinishAction = {
progressFinishAd {
if (resultFile != null) {
startActivity(Intent(this, PdfActivity::class.java).apply {
putExtra("path", resultFile?.absolutePath ?: "")
})
} else {
toast("split pdf failed")
}
finish()
}
}
pdfViewModel.splitPdf(srcPath, newPath, splitIndex, finishAction = {
resultFile = it
isFinishBoolean = true
})
}
DO_SAVE_PDF -> {
muPDFCore?.save()
muPDFCore = null
progressFinishAction = {
progressFinishAd {
startActivity(Intent(this, PdfActivity::class.java).apply {
putExtra("path", srcPath)
})
finish()
}
}
lifecycleScope.launch {
delay(Random.nextLong(1500, 2500))
isFinishBoolean = true
}
}
DO_MERGE_PDF -> {
progressFinishAction = {
progressFinishAd {
startActivity(Intent(this, PdfActivity::class.java).apply {
putExtra("path", newPath)
})
finish()
}
}
pdfViewModel.mergePdf(newPath) {
isFinishBoolean = true
}
}
}
startProgress()
}
private fun startProgress() = lifecycleScope.launch(Dispatchers.Main) {
while (isActive) {
if (isFinishBoolean) {
binding.progressBar.progress = 100
delay(200)
break
} else {
binding.progressBar.progress += 2
}
delay(500)
}
progressFinishAction?.invoke()
}
private fun initSpPa() {
doWhat = intent?.extras?.getString("doWhat", "") ?: ""
srcPath = intent?.extras?.getString("srcPath", "") ?: ""
pwd = intent.extras?.getString("pwd")
newPath = intent?.extras?.getString("newPath", "") ?: ""
splitIndex = intent.extras?.getString("splitIndex")?.split(",")?.map { it.toInt() } ?: listOf()
LogEx.logDebug(TAG, "initSpPa doWhat=$doWhat srcPath=$srcPath pwd=$pwd newPath=$newPath splitIndex=$splitIndex")
}
companion object {
var muPDFCore: MuPDFCore? = null
}
override fun onDestroy() {
super.onDestroy()
muPDFCore?.onDestroy()
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import android.content.Intent
import androidx.activity.addCallback
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
import com.base.pdfoneread.bean.ConstObject.DO_MERGE_PDF
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.databinding.ActivityPdfMergeBinding
import com.base.pdfoneread.ui.BaseActivity
import com.base.pdfoneread.ui.views.NameDialog.showDocumentRenameDialog
import com.base.pdfoneread.ui.views.PwdDialog.showPdfPwdDialog
import com.base.pdfoneread.utils.KotlinExt.toFormatTime2
import com.base.pdfoneread.utils.LogEx
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.BlockingQueue
class PdfMergeActivity : BaseActivity<ActivityPdfMergeBinding>() {
private val TAG = "PdfMergeActivity"
override val binding: ActivityPdfMergeBinding by lazy {
ActivityPdfMergeBinding.inflate(layoutInflater)
}
private lateinit var pdfViewModel: PdfViewModel
private lateinit var adapter: PdfMergeAdapter
override fun onResume() {
super.onResume()
// updateAppLanguage(MyApplication.pdfMergeLanguage) {
// MyApplication.pdfMergeLanguage = it
// }
}
override fun initView() {
pdfViewModel = ViewModelProvider(this)[PdfViewModel::class.java]
initAdapter()
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
finish()
}
binding.flFanhui.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.tvAdd.setOnClickListener {
finish()
}
binding.tvBtnNext.setOnClickListener {
verificationPasswordDialogs {
showDocumentRenameDialog(name = "Merge_${System.currentTimeMillis().toFormatTime2()}", okAction = { name ->
startActivity(Intent(this, PdfLoadingActivity::class.java).apply {
putExtra("doWhat", DO_MERGE_PDF)
putExtra("newPath", pdfViewModel.createNewPdfPath(this@PdfMergeActivity, name))
})
finish()
})
}
}
}
private fun verificationPasswordDialogs(callBack: () -> Unit) {
val queue: BlockingQueue<DocumentBean> = ArrayBlockingQueue(1)
val pwdItemList = mergePdfList.filter { it.state == 1 }.toMutableList()
if (pwdItemList.isNotEmpty()) {
LogEx.logDebug(TAG, "verificationPasswordDialogs1")
val verifiedList = arrayListOf<DocumentBean>()
val first = pwdItemList[0]
queue.put(first)
pwdItemList.removeAt(0)
LogEx.logDebug(TAG, "verificationPasswordDialogs2")
lifecycleScope.launch(Dispatchers.IO) {
while (isActive) {
val item: DocumentBean = queue.take()
LogEx.logDebug(TAG, "pwdItem =${item.path}")
if (item.path == "Cancel") {
break
}
launch(Dispatchers.Main) {
showPdfPwdDialog(item.state, item.path, isCheckPwd = true, verificationAction = { pwd ->
item.password = pwd
verifiedList.add(item)
if (pwdItemList.isNotEmpty()) {
val next = pwdItemList[0]
queue.put(next)
pwdItemList.removeAt(0)
} else {
queue.put(DocumentBean(path = "Cancel"))
}
}, cancelAction = {
cancel()
})
}
}
LogEx.logDebug(TAG, "verificationPasswordDialogs3 ${verifiedList.size}")
verifiedList.forEach { verifiedItem ->
mergePdfList.find { it.path == verifiedItem.path }?.password = verifiedItem.password
}
mergePdfList.forEach {
LogEx.logDebug(TAG, "密码=" + it.password)
}
launch(Dispatchers.Main) {
callBack.invoke()
}
}
} else {
callBack.invoke()
}
}
private fun initAdapter() {
val callBack = PdfMergeItemTouchHelperCallBack()
val itemTouchHelper = ItemTouchHelper(callBack)
itemTouchHelper.attachToRecyclerView(binding.rv)
adapter = PdfMergeAdapter(itemTouchHelper, callBack)
adapter.removeAction = {
mergePdfList.remove(it)
binding.tvBtnNext.isEnabled = mergePdfList.size >= 2
}
binding.rv.adapter = adapter
callBack.changeListOrder = { olderPosition, newPosition ->
val bean = mergePdfList[olderPosition]
mergePdfList.remove(bean)
mergePdfList.add(newPosition, bean)
mergePdfList.forEach {
LogEx.logDebug(TAG, "mergePdfList ${it.path}")
}
adapter.items.forEach {
LogEx.logDebug(TAG, "items ${it.path}")
}
}
mergePdfList.let { adapter.submitList(it) }
binding.tvBtnNext.isEnabled = mergePdfList.size >= 2
}
companion object {
val mergePdfList: ArrayList<DocumentBean> = arrayListOf()
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import android.annotation.SuppressLint
import android.content.Context
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.databinding.ItemPdfMergeBinding
import com.base.pdfoneread.utils.KotlinExt.toFormatSize
import com.base.pdfoneread.utils.KotlinExt.toFormatTime4
import com.base.pdfoneread.utils.LogEx
import com.base.pdfoneread.utils.XmlEx.inflate
import com.chad.library.adapter4.BaseQuickAdapter
import java.io.File
class PdfMergeAdapter(
val itemTouchHelper: ItemTouchHelper,
val callBack: PdfMergeItemTouchHelperCallBack
) : BaseQuickAdapter<DocumentBean, PdfMergeAdapter.PdfMergeViewHolder>() {
private val TAG = "PdfMergeAdapter"
var removeAction: ((item: DocumentBean) -> Unit)? = null
inner class PdfMergeViewHolder(view: View) : RecyclerView.ViewHolder(view)
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
override fun onBindViewHolder(holder: PdfMergeViewHolder, position: Int, item: DocumentBean?) {
if (item == null) return
val binding = ItemPdfMergeBinding.bind(holder.itemView)
val file = File(item.path)
binding.tvName.text = file.name
binding.tvInfo.text = file.lastModified().toFormatTime4() + " " + file.length().toFormatSize()
if (item.state == 0) {
binding.iv.setImageResource(R.mipmap.rv_pdf)
} else {
binding.iv.setImageResource(R.mipmap.rv_pdf_s)
}
binding.flClose.setOnClickListener {
remove(item)
removeAction?.invoke(item)
}
binding.ivMove.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
if (event?.action == MotionEvent.ACTION_DOWN) {
callBack.enableLongPress = true
LogEx.logDebug(TAG, "ACTION_DOWN ${System.currentTimeMillis()}")
// 长按时启动拖动
itemTouchHelper.startDrag(holder)
return true
}
return false
}
})
}
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): PdfMergeViewHolder {
return PdfMergeViewHolder(R.layout.item_pdf_merge.inflate(parent))
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.base.pdfoneread.utils.LogEx
class PdfMergeItemTouchHelperCallBack : ItemTouchHelper.Callback() {
var changeListOrder: ((olderPosition: Int, newPosition: Int) -> Unit)? = null
var enableLongPress: Boolean = false
private val TAG = "PdfMergeItemTouchHelperCallBack"
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
//支持上下左右拖动
// ACTION_STATE_IDLE item默认滑动方向
return makeMovementFlags(
ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.START or ItemTouchHelper.END,
ItemTouchHelper.ACTION_STATE_IDLE
)
// 禁用默认的拖动和滑动
// return makeMovementFlags(0, 0);
}
/**
* 拖拽结束后(手指抬起)会回调的方法
*/
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
//更新item holder对应位置
recyclerView.adapter?.notifyItemMoved(
viewHolder.adapterPosition,
target.adapterPosition
)
changeListOrder?.invoke(viewHolder.layoutPosition, target.layoutPosition)
enableLongPress = false
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
override fun isLongPressDragEnabled(): Boolean {
LogEx.logDebug(TAG, "isLongPressDragEnabled $enableLongPress ${System.currentTimeMillis()}")
return enableLongPress
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
// 当没有动作时,取消拖动状态
viewHolder?.itemView?.setPressed(false)
} else if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
// 当滑动时,设置拖动状态
viewHolder?.itemView?.setPressed(true)
}
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.PdfPageBean
import com.base.pdfoneread.databinding.ItemPdfPagerBinding
import com.base.pdfoneread.databinding.ItemPdfPagerSplitBinding
import com.base.pdfoneread.utils.PdfBoxUtils
import com.base.pdfoneread.utils.XmlEx.inflate
import com.chad.library.adapter4.BaseQuickAdapter
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
class PdfPagerAdapter(
val pdfPath: String,
val uri: String? = null,
val itemLayout: Int = R.layout.item_pdf_pager,
) : BaseQuickAdapter<PdfPageBean, PdfPagerAdapter.PdfPagerViewHolder>() {
var mPassword: String? = null
var selectAction: ((enable: Boolean, allSelect: Boolean) -> Unit)? = null
var clickAction: ((pageIndex: Int) -> Unit)? = null
inner class PdfPagerViewHolder(view: View) : ViewHolder(view)
var corePoolSize = 4 // 核心线程数
var maximumPoolSize = 10 // 最大线程数
var keepAliveTime: Long = 120 // 非核心线程空闲存活时间
var threadPoolExecutor = ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
LinkedBlockingQueue()
)
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: PdfPagerViewHolder, position: Int, item: PdfPageBean?) {
if (item == null) return
when (itemLayout) {
R.layout.item_pdf_pager -> {
val binding = ItemPdfPagerBinding.bind(holder.itemView)
val context = holder.itemView.context
binding.tvPagerIndex.isSelected = item.isSelect
binding.tvPagerIndex.text = (item.pageIndex + 1).toString()
binding.flBorder.isSelected = item.isSelect
if (item.pageDrawable != null) {
binding.ivPager.setImageDrawable(item.pageDrawable)
} else {
loadPagerDrawable(context, item, binding.root, binding.ivPager)
}
binding.root.setOnClickListener {
clickAction?.invoke(item.pageIndex)
}
}
R.layout.item_pdf_pager_split -> {
val binding = ItemPdfPagerSplitBinding.bind(holder.itemView)
binding.ivSelector.isSelected = item.isSelect
if (item.pageDrawable != null) {
binding.ivPager.setImageDrawable(item.pageDrawable)
} else {
loadPagerDrawable(context, item, binding.root, binding.ivPager, 1.5f)
}
binding.ivSelector.setOnClickListener {
item.isSelect = !item.isSelect
notifyItemChanged(position, "aaa")
selectAction?.invoke(items.any { it.isSelect }, items.all { it.isSelect })
}
}
}
}
private fun loadPagerDrawable(
context: Context,
item: PdfPageBean,
itemView: View,
iv: ImageView,
scale: Float = 1f
) {
threadPoolExecutor.execute {
runCatching {
val drawable = PdfBoxUtils.getPdfDrawablePage(context, pdfPath, mPassword, uri, item.pageIndex, scale)
item.pageDrawable = drawable
itemView.post {
item.pageDrawable?.let {
iv.setImageDrawable(it)
}
}
}
}
}
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): PdfPagerViewHolder {
return PdfPagerViewHolder(itemLayout.inflate(parent))
}
@SuppressLint("NotifyDataSetChanged")
fun toggleSelect(select: Boolean) {
items.forEach { it.isSelect = select }
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun changeSelectPager(page: Int) {
runCatching {
items.forEach { it.isSelect = false }
items[page].isSelect = true
}
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun setPassword(password: String) {
mPassword = password
notifyDataSetChanged()
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.view.View
import androidx.activity.addCallback
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.base.pdfoneread.R
import com.base.pdfoneread.ads.AdmobHelper
import com.base.pdfoneread.ads.admob.AdmobInterstitialUtils
import com.base.pdfoneread.bean.ConstObject.DO_LOCK_PDF
import com.base.pdfoneread.bean.ConstObject.DO_MERGE_PDF
import com.base.pdfoneread.bean.ConstObject.DO_SPLIT_PDF
import com.base.pdfoneread.bean.ConstObject.DO_UNLOCK_PDF
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.databinding.ActivityPdfSelectBinding
import com.base.pdfoneread.ui.BaseActivity
import com.base.pdfoneread.ui.document.DocumentAdapter
import com.base.pdfoneread.ui.document.getPdfDocument
import com.base.pdfoneread.ui.views.PwdDialog.showPdfPwdDialog
import com.base.pdfoneread.utils.BarUtils
import com.base.pdfoneread.utils.LogEx
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class PdfSelectActivity : BaseActivity<ActivityPdfSelectBinding>() {
private val TAG = "PdfSelectActivity"
private lateinit var pdfViewModel: PdfViewModel
private lateinit var adapter: DocumentAdapter
private var doWhat: String = ""
override val binding: ActivityPdfSelectBinding by lazy {
ActivityPdfSelectBinding.inflate(layoutInflater)
}
override fun onResume() {
super.onResume()
// updateAppLanguage(MyApplication.pdfSelectLanguage) {
// MyApplication.pdfSelectLanguage = it
// }
}
override fun initView() {
// if (checkNeedRecreate(MyApplication.pdfSelectLanguage)) {
// return
// }
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.WHITE)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
pdfViewModel = ViewModelProvider(this)[PdfViewModel::class.java]
doWhat = intent.extras?.getString("doWhat", "") ?: ""
LogEx.logDebug(TAG, "doWhat=$doWhat")
initAdapter()
when (doWhat) {
DO_SPLIT_PDF -> {
binding.tvBtnNext.visibility = View.GONE
binding.tvSelectTip.text = getString(R.string.select_a_project)
getPdfData(2)
}
DO_MERGE_PDF -> {
binding.tvSelectTip.text = getString(R.string.select_a_project)
getPdfData(1)
}
DO_LOCK_PDF -> {
binding.tvBtnNext.visibility = View.GONE
binding.tvSelectTip.text = getString(R.string.select_a_project)
getPdfData(3)
}
DO_UNLOCK_PDF -> {
binding.tvBtnNext.visibility = View.GONE
binding.tvSelectTip.text = getString(R.string.select_a_project)
getPdfData(3)
}
}
}
private fun getPdfData(uiType: Int) {
lifecycleScope.launch(Dispatchers.IO) {
val list = getPdfDocument(this@PdfSelectActivity)
list.forEach { it.uiType = uiType }
launch(Dispatchers.Main) {
refreshUI(list)
}
}
}
private fun refreshUI(list: List<DocumentBean>) {
adapter.submitList(list)
binding.llEmpty.isVisible = list.isEmpty()
binding.progressBar.visibility = View.GONE
}
override fun initListener() {
super.initListener()
// if (checkNeedRecreate(MyApplication.pdfSelectLanguage)) {
// return
// }
onBackPressedDispatcher.addCallback {
finishToMain()
}
binding.flFanhui.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.tvBtnNext.setOnClickListener {
if (doWhat == DO_MERGE_PDF) {
val selectList = adapter.items.filter { it.isSelect }
PdfMergeActivity.mergePdfList.clear()
PdfMergeActivity.mergePdfList.addAll(selectList)
startActivity(Intent(this, PdfMergeActivity::class.java))
}
}
}
@SuppressLint("StringFormatMatches")
private fun initAdapter() {
adapter = DocumentAdapter(this)
adapter.itemClick = {
if (doWhat == DO_SPLIT_PDF) {
if (it.state == 0) {
startActivity(Intent(this, PdfSplitActivity::class.java).apply {
putExtra("path", it.path)
})
} else {
showPdfPwdDialog(
state = it.state,
path = it.path,
isCheckPwd = true,
verificationAction = { pwd ->
startActivity(Intent(this, PdfSplitActivity::class.java).apply {
putExtra("path", it.path)
putExtra("pwd", pwd)
})
})
}
}
if (doWhat == DO_LOCK_PDF) {
showPdfPwdDialog(state = it.state, path = it.path, encryptionAction = {
if (AdmobHelper.canCommonShowAd()) {
AdmobInterstitialUtils.showInterstitialAd(this) { flag ->
adapter.remove(it)
binding.llEmpty.isVisible = adapter.items.isEmpty()
}
} else {
adapter.remove(it)
binding.llEmpty.isVisible = adapter.items.isEmpty()
}
})
}
if (doWhat == DO_UNLOCK_PDF) {
showPdfPwdDialog(state = it.state, path = it.path, encryptionAction = {
if (AdmobHelper.canCommonShowAd()) {
AdmobInterstitialUtils.showInterstitialAd(this) { flag ->
adapter.remove(it)
binding.llEmpty.isVisible = adapter.items.isEmpty()
}
} else {
adapter.remove(it)
binding.llEmpty.isVisible = adapter.items.isEmpty()
}
})
}
}
adapter.selectAction = {
LogEx.logDebug(TAG, "selectAction $it")
if (it == 0) {
binding.tvSelectTip.visibility = View.INVISIBLE
binding.tvBtnNext.isEnabled = false
} else {
binding.tvBtnNext.isEnabled = true
binding.tvSelectTip.visibility = View.VISIBLE
binding.tvSelectTip.text = getString(R.string.items_has_been_selected, it)
}
}
binding.rv.adapter = adapter
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import android.content.Intent
import android.graphics.Color
import androidx.activity.addCallback
import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.ConstObject
import com.base.pdfoneread.databinding.ActivityPdfSplitBinding
import com.base.pdfoneread.ui.BaseActivity
import com.base.pdfoneread.ui.views.NameDialog.showDocumentRenameDialog
import com.base.pdfoneread.utils.BarUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class PdfSplitActivity : BaseActivity<ActivityPdfSplitBinding>() {
private lateinit var pdfViewModel: PdfViewModel
private lateinit var pdfPagerAdapter: PdfPagerAdapter
private var path: String = ""
private var pwd: String? = ""
override val binding: ActivityPdfSplitBinding by lazy {
ActivityPdfSplitBinding.inflate(layoutInflater)
}
override fun onResume() {
super.onResume()
// updateAppLanguage(MyApplication.pdfSplitLanguage) {
// MyApplication.pdfSplitLanguage = it
// }
}
override fun initView() {
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.WHITE)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
pdfViewModel = ViewModelProvider(this)[PdfViewModel::class.java]
path = intent.extras?.getString("path", "") ?: ""
pwd = intent.extras?.getString("pwd", "") ?: ""
pdfViewModel.password = pwd
initAdapter()
pdfViewModel.initPdfPageRv = { items ->
lifecycleScope.launch(Dispatchers.Main) {
pdfPagerAdapter.submitList(items)
}
}
pdfViewModel.iniPdfPage(this, path)
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
finishToMain()
}
binding.flFanhui.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.ivSelector.setOnClickListener {
binding.ivSelector.isSelected = !binding.ivSelector.isSelected
pdfPagerAdapter.toggleSelect(binding.ivSelector.isSelected)
}
binding.tvBtnSplit.setOnClickListener {
val splitIndex = pdfPagerAdapter.items.filter { it.isSelect }.map { it.pageIndex }
showDocumentRenameDialog(okAction = { newName ->
startActivity(Intent(this, PdfLoadingActivity::class.java).apply {
putExtra("doWhat", ConstObject.DO_SPLIT_PDF)
putExtra("srcPath", path)
putExtra("pwd", pwd)
putExtra("newPath", pdfViewModel.createNewPdfPath(this@PdfSplitActivity, newName))
putExtra("splitIndex", splitIndex.joinToString(separator = ","))
})
finish()
})
}
}
private fun initAdapter() {
pdfPagerAdapter = PdfPagerAdapter(path, null, R.layout.item_pdf_pager_split)
pdfPagerAdapter.mPassword = pwd
pdfPagerAdapter.selectAction = { enable, allSelect ->
binding.tvBtnSplit.isEnabled = enable
binding.ivSelector.isSelected = allSelect
}
binding.rv.adapter = pdfPagerAdapter
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.pdf
import android.content.Context
import android.net.Uri
import android.os.Environment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.artifex.mupdfdemo.MuPDFCore
import com.artifex.mupdfdemo.OutlineActivityData
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.ConstObject.MIME_TYPE_PDF
import com.base.pdfoneread.bean.PdfPageBean
import com.base.pdfoneread.ui.pdf.PdfMergeActivity.Companion.mergePdfList
import com.base.pdfoneread.utils.LogEx
import com.base.pdfoneread.utils.PdfBoxUtils
import com.base.pdfoneread.utils.UriUtils.readFileToByteArray
import com.tom_roush.pdfbox.multipdf.PDFMergerUtility
import com.tom_roush.pdfbox.pdmodel.PDDocument
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class PdfViewModel : ViewModel() {
private val TAG = "PdfViewModel"
var password: String? = null
var initPdfPageRv: ((items: List<PdfPageBean>) -> Unit)? = null
fun openFile(context: Context, path: String, uri: String? = null): MuPDFCore? {
var muPDFCore: MuPDFCore? = null
try {
muPDFCore = if (uri == null)
MuPDFCore(context, path)
else
MuPDFCore(context, readFileToByteArray(context, Uri.parse(uri)), MIME_TYPE_PDF)
// 新建:删除旧的目录数据
OutlineActivityData.set(null)
} catch (e: java.lang.Exception) {
return null
} catch (e: OutOfMemoryError) {
return null
}
return muPDFCore
}
fun iniPdfPage(pageCount: Int) {
val list = arrayListOf<PdfPageBean>()
repeat(pageCount) {
list.add(PdfPageBean(it))
}
initPdfPageRv?.invoke(list)
}
fun iniPdfPage(context: Context, filePath: String, uri: String? = null) = viewModelScope.launch(Dispatchers.IO) {
val list = arrayListOf<PdfPageBean>()
val number = PdfBoxUtils.getNumberOfPages(context, filePath, password, uri)
repeat(number) {
list.add(PdfPageBean(it))
}
initPdfPageRv?.invoke(list)
}
private fun createAppDocumentDir(context: Context): File {
val appName = context.resources.getString(R.string.app_name)
val appDir = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), appName)
if (!appDir.exists()) {
appDir.mkdirs()
}
return appDir
}
fun createNewPdfPath(context: Context, name: String): String {
val appDir = createAppDocumentDir(context)
val child = if (name.endsWith(".pdf")) name else "$name.pdf"
val mergeFile = File(appDir, child)
mergeFile.createNewFile()
LogEx.logDebug(TAG, "mergeFile ${mergeFile.absolutePath}")
return mergeFile.absolutePath
}
fun splitPdf(
srcPath: String,
newPath: String,
splitIndex: List<Int>,
finishAction: (newFile: File?) -> Unit
) = Thread {
try {
// 加载现有 PDF 文档
val sourceDocument = PDDocument.load(File(srcPath), password)
LogEx.logDebug(TAG, "sourceDocument open")
// 创建新的 PDF 文档
val newDocument = PDDocument()
// 遍历指定的页面范围
splitIndex.forEach { index ->
val page = sourceDocument.getPage(index)
newDocument.addPage(page)
}
// 保存新的 PDF 文档
newDocument.save(newPath)
newDocument.close()
sourceDocument.close()
} catch (e: Exception) {
LogEx.logDebug(TAG, "splitPdf error")
finishAction.invoke(null)
return@Thread
}
finishAction.invoke(File(newPath))
}.start()
fun mergePdf(mergePath: String, finishAction: (success: Boolean) -> Unit) = Thread {
var isSuccess: Boolean = false
try {
val mergerUtility = PDFMergerUtility()
mergerUtility.destinationFileName = mergePath
//解密
PdfMergeActivity.mergePdfList.filter { it.state == 1 }.forEach {
PdfBoxUtils.clearPassword(it.path, it.password)
}
LogEx.logDebug(TAG, "mergePdf ${mergePdfList.size}")
PdfMergeActivity.mergePdfList.forEach { documentBean ->
LogEx.logDebug(TAG, "mergePdf item= ${documentBean.path} ${documentBean.state}")
//带密码 mergerUtility.addSource(inputStream) 不行
mergerUtility.addSource(File(documentBean.path))
// if (documentBean.state == 0) {
// mergerUtility.addSource(File(documentBean.path))
// } else {
// LogEx.logDebug(TAG, "mergePdf password=${documentBean.password}")
// try {
// val pdfDocument = PDDocument.load(File(documentBean.path), documentBean.password)
// LogEx.logDebug(TAG, "mergePdf pdfDocument ${pdfDocument.numberOfPages}")
// val byteArrayOutputStream = ByteArrayOutputStream()
// pdfDocument.save(byteArrayOutputStream)
// LogEx.logDebug(TAG, "mergePdf byteArrayOutputStream ${byteArrayOutputStream.size()}")
// pdfDocument.close()
// val inputStream = ByteArrayInputStream(byteArrayOutputStream.toByteArray())
// LogEx.logDebug(TAG, "mergePdf inputStream")
// mergerUtility.addSource(inputStream)
// } catch (e: Exception) {
// LogEx.logDebug(TAG, "mergePdf Exception ${e.printStackTrace()}")
// }
// LogEx.logDebug(TAG, "mergePdf inputStream")
// }
}
mergerUtility.mergeDocuments(null)
//重新加密
PdfMergeActivity.mergePdfList.filter { it.state == 1 }.forEach {
val flag = PdfBoxUtils.setPassword(it.path, it.password, it.password)
LogEx.logDebug(TAG, "重新加密 flag=$flag ${it.path} ${it.password}")
}
mergePdfList.clear()
LogEx.logDebug(TAG, "mergePdf finish")
isSuccess = true
} catch (e: Exception) {
}
finishAction.invoke(isSuccess)
}.start()
}
\ No newline at end of file
package com.base.pdfoneread.ui.views
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfoneread.databinding.DialogDeleteBinding
import com.base.pdfoneread.databinding.DialogDocumentDetailBinding
import com.base.pdfoneread.databinding.DialogDocumentHomeMoreBinding
import com.base.pdfoneread.ui.views.NameDialog.showDocumentRenameDialog
import com.base.pdfoneread.utils.IntentShareUtils.documentShare
import com.base.pdfoneread.utils.KotlinExt.toFormatSize
import com.base.pdfoneread.utils.KotlinExt.toFormatTime4
import com.base.pdfoneread.utils.KotlinExt.toFormatTime6
import com.base.pdfoneread.utils.SpStringUtils
import com.base.pdfoneread.utils.SpStringUtils.LAST_VIEW_KEY
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import java.io.File
object DocumentDialog {
@SuppressLint("SetTextI18n")
fun Context.showDocumentHomeMoreDialog(
item: DocumentBean,
dialogCallBack: DialogCallBack
): BottomSheetDialog {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogDocumentHomeMoreBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
val file = File(item.path)
binding.tvName.text = file.name
binding.tvInfo.text = file.lastModified().toFormatTime4() + " " + file.length().toFormatSize()
if (item.isBookmarked) {
binding.ivBookmark.setImageResource(R.mipmap.r_star_s)
} else {
binding.ivBookmark.setImageResource(R.mipmap.star)
}
when (item.type) {
TYPE_WORD -> {
binding.ivDocument.setImageResource(R.mipmap.rv_word)
}
TYPE_EXCEL -> {
binding.ivDocument.setImageResource(R.mipmap.rv_excel)
}
TYPE_PPT -> {
binding.ivDocument.setImageResource(R.mipmap.rv_ppt)
}
}
binding.llRename.setOnClickListener {
showDocumentRenameDialog(file.name, okAction = { newName ->
dialog.dismiss()
dialogCallBack.renameDocumentBean(file, newName)
})
}
binding.llDetail.setOnClickListener {
showDocumentDetail(item.path)
}
binding.llShare.setOnClickListener {
documentShare(item)
}
binding.llDelete.setOnClickListener {
dialog.dismiss()
showDeleteDialog {
dialogCallBack.deleteDocument(item)
}
}
return dialog
}
fun Context.showDocumentDetail(path: String) {
val dialog = AlertDialog.Builder(this).create()
val binding = DialogDocumentDetailBinding.inflate(LayoutInflater.from(this))
dialog.setView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val params = dialog.window?.attributes
params?.gravity = Gravity.CENTER
dialog.window?.attributes = params
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
val file = File(path)
binding.tvName.text = file.name
binding.tvPath.text = file.absolutePath
val lastView = SpStringUtils.getSpStringList(LAST_VIEW_KEY).find { it.contains(file.absolutePath) }
if (lastView != null) {
val lastTime = lastView.split("_/_")[1]
binding.tvLastView.text = lastTime.toLong().toFormatTime6()
} else {
binding.tvLastView.text = file.lastModified().toFormatTime6()
}
binding.tvLastChange.text = file.lastModified().toFormatTime6()
binding.tvFileSize.text = file.length().toFormatSize()
binding.tvBtnOk.setOnClickListener {
dialog.dismiss()
}
}
fun Context.showDeleteDialog(deleteAction: () -> Unit) {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogDeleteBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.tvCancel.setOnClickListener {
dialog.dismiss()
}
binding.tvDelete.setOnClickListener {
dialog.dismiss()
deleteAction.invoke()
}
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.views
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import androidx.core.widget.addTextChangedListener
import com.base.pdfoneread.R
import com.base.pdfoneread.databinding.DialogDocumentRenameBinding
import com.base.pdfoneread.utils.KotlinExt.toFormatTime2
import com.base.pdfoneread.utils.ToastUtils.toast
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
object NameDialog {
/**
* 重命名
*/
fun Context.showDocumentRenameDialog(
name: String? = null,
okAction: ((newName: String) -> Unit)? = null,
dismissAction: (() -> Unit)? = null
) {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogDocumentRenameBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
val window = dialog.window
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.edit.addTextChangedListener {
binding.tvOk.isEnabled = !it.isNullOrEmpty()
}
val tempName = "Split_" + System.currentTimeMillis().toFormatTime2()
binding.edit.setText(name ?: tempName)
if (name == null) {
binding.edit.selectAll()
} else {
val nameS = name.split(".")[0]
binding.edit.setSelection(0, nameS.length)
}
binding.edit.requestFocus()
binding.tvCancel.setOnClickListener {
dialog.dismiss()
}
binding.tvOk.setOnClickListener {
dialog.dismiss()
val newName = binding.edit.text.toString()
if (newName.isEmpty()) {
toast("name can't be empty!")
return@setOnClickListener
}
okAction?.invoke(newName)
}
dialog.setOnDismissListener {
dismissAction?.invoke()
}
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.views
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import androidx.core.content.FileProvider
import androidx.core.widget.addTextChangedListener
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.databinding.DialogPageNumberBinding
import com.base.pdfoneread.databinding.DialogPdfHomeMoreBinding
import com.base.pdfoneread.databinding.DialogPdfMoreBinding
import com.base.pdfoneread.ui.document.saveBookmarkChange
import com.base.pdfoneread.ui.pdf.PdfActivity
import com.base.pdfoneread.ui.pdf.PdfActivity.Companion.jumpMerge
import com.base.pdfoneread.ui.pdf.PdfActivity.Companion.jumpPdfActivity
import com.base.pdfoneread.ui.pdf.PdfActivity.Companion.jumpSplit
import com.base.pdfoneread.ui.views.DocumentDialog.showDeleteDialog
import com.base.pdfoneread.ui.views.DocumentDialog.showDocumentDetail
import com.base.pdfoneread.ui.views.NameDialog.showDocumentRenameDialog
import com.base.pdfoneread.ui.views.PwdDialog.showPdfPwdDialog
import com.base.pdfoneread.utils.IntentShareUtils
import com.base.pdfoneread.utils.KotlinExt.toFormatSize
import com.base.pdfoneread.utils.KotlinExt.toFormatTime
import com.base.pdfoneread.utils.LogEx
import com.base.pdfoneread.utils.NumberRangeFilter
import com.base.pdfoneread.utils.SpStringUtils
import com.base.pdfoneread.utils.SpStringUtils.BOOKMARK_KEY
import com.base.pdfoneread.utils.ToastUtils.toast
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import java.io.File
object PdfDialog {
//pdf首页弹窗
@SuppressLint("NotifyDataSetChanged")
fun Activity.showPdfHomeMoreDialog(
item: DocumentBean,
dialogCallBack: DialogCallBack
): BottomSheetDialog {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogPdfHomeMoreBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
val file = File(item.path)
binding.tvName.text = file.name
binding.tvInfo.text = file.lastModified().toFormatTime() + " " + file.length().toFormatSize()
if (item.isBookmarked) {
binding.ivBookmark.setImageResource(R.mipmap.r_star_s)
} else {
binding.ivBookmark.setImageResource(R.mipmap.star)
}
binding.ivBookmark.setOnClickListener {
item.isBookmarked = !item.isBookmarked
if (item.isBookmarked) {
binding.ivBookmark.setImageResource(R.mipmap.r_star_s)
} else {
binding.ivBookmark.setImageResource(R.mipmap.star)
}
dialogCallBack.changeBookmark(item.path, item.isBookmarked)
}
binding.llRename.setOnClickListener {
showDocumentRenameDialog(file.name, okAction = { newName ->
dialog.dismiss()
dialogCallBack.renameDocumentBean(file, newName)
})
}
binding.llSplit.setOnClickListener {
dialog.dismiss()
jumpPdfActivity(this, item)
}
binding.llMerge.setOnClickListener {
dialog.dismiss()
PdfActivity.jumpMerge(this)
}
binding.llDelete.setOnClickListener {
dialog.dismiss()
showDeleteDialog {
dialogCallBack.deleteDocument(item)
}
}
binding.llDetail.setOnClickListener {
showDocumentDetail(item.path)
}
binding.llShare.setOnClickListener {
runCatching {
item.uri?.let {
val intent = IntentShareUtils.sharePdfIntent(it)
startActivity(intent)
}
}
}
if (item.state == 1) {
binding.ivPdf.setImageResource(R.mipmap.rv_pdf_s)
binding.tvLock.text = getString(R.string.unlock_pdf)
}
if (item.state == 0) {
binding.ivPdf.setImageResource(R.mipmap.rv_pdf)
binding.tvLock.text = getString(R.string.lock_pdf)
}
binding.llLock.setOnClickListener {
showPdfPwdDialog(state = item.state, path = item.path,
firstDialog = dialog,
isCheckPwd = false,
encryptionAction = {
dialog.dismiss()
dialogCallBack.changePdfLock(item)
}
)
}
dialog.setOnDismissListener {
}
return dialog
}
fun Activity.showPdfMoreDialog(
pdfActivity: PdfActivity,
pageNumber: Int,
pafPath: String,
uri: String? = null,
pwd: String? = null,
) {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogPdfMoreBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.llJump.setOnClickListener {
showJumpPageNumberDialog(pageNumber) { pageIndex ->
dialog.dismiss()
pdfActivity.jumpPage(pageIndex)
}
}
binding.llMerge.setOnClickListener {
dialog.dismiss()
jumpMerge(pdfActivity)
}
binding.llSplit.setOnClickListener {
dialog.dismiss()
jumpSplit(pdfActivity, pafPath, uri, pwd)
}
binding.llDetail.setOnClickListener {
showDocumentDetail(pafPath)
}
val bookmarkList = SpStringUtils.getSpStringList(BOOKMARK_KEY)
var isBookmarked = bookmarkList.contains(pafPath)
if (isBookmarked) {
binding.ivBookmark.setImageResource(R.mipmap.r_star_s)
} else {
binding.ivBookmark.setImageResource(R.mipmap.star)
}
binding.ivBookmark.setOnClickListener {
isBookmarked = !isBookmarked
if (isBookmarked) {
binding.ivBookmark.setImageResource(R.mipmap.r_star_s)
} else {
binding.ivBookmark.setImageResource(R.mipmap.star)
}
saveBookmarkChange(isBookmarked, pafPath)
}
binding.llShare.setOnClickListener {
dialog.dismiss()
runCatching {
val pkg = this.packageName
LogEx.logDebug("showPdfMoreDialog", "pkg=$pkg")
val uri = FileProvider.getUriForFile(
this, this.packageName + ".provider", File(pafPath)
)
startActivity(Intent.createChooser(IntentShareUtils.sharePdfIntent(uri), "Share PDF"))
}
}
}
fun Context.showJumpPageNumberDialog(pageNumber: Int, okAction: ((pageIndex: Int) -> Unit)?) {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogPageNumberBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
val window = dialog.window
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.edit.filters = arrayOf(NumberRangeFilter(1, pageNumber + 1))
binding.edit.hint = "1 - ${pageNumber + 1}"
binding.edit.addTextChangedListener {
binding.tvOk.isEnabled = !it.isNullOrEmpty()
}
binding.edit.requestFocus()
binding.tvOk.setOnClickListener {
val number = binding.edit.text.toString()
if (number.isEmpty()) {
toast("number can't be empty!")
return@setOnClickListener
}
dialog.dismiss()
okAction?.invoke(number.toInt() - 1)
}
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.views
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.text.method.PasswordTransformationMethod
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import androidx.core.widget.addTextChangedListener
import com.base.pdfoneread.R
import com.base.pdfoneread.databinding.DialogPdfPasswordBinding
import com.base.pdfoneread.utils.LogEx
import com.base.pdfoneread.utils.PdfBoxUtils
import com.base.pdfoneread.utils.PdfBoxUtils.checkPwd
import com.base.pdfoneread.utils.ToastUtils.toast
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import java.io.File
object PwdDialog {
@SuppressLint("SetTextI18n")
fun Context.showPdfPwdDialog(
state: Int,
path: String = "",
uri: String? = null,
firstDialog: Dialog? = null,
isCheckPwd: Boolean = false,
verificationAction: ((pwd: String) -> Unit)? = null,
encryptionAction: (() -> Unit)? = null,
cancelAction: (() -> Unit)? = null,
) {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogPdfPasswordBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
val window = dialog.window
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
if (!isCheckPwd) {
if (state == 1) {
binding.tvTittle.text = getString(R.string.delete_password)
binding.tvTip.text = getString(R.string.delete_password_the_file_is_not_password_protected)
}
if (state == 0) {
binding.tvTittle.text = getString(R.string.set_password)
binding.tvTip.text = getString(R.string.set_password_protection_pdf)
}
} else {
binding.tvTittle.text = getString(R.string.input_password)
val file = File(path)
binding.tvTip.text = getString(R.string.password_protected, file.name)
binding.tvInputTip.visibility = View.VISIBLE
}
binding.edit.requestFocus()
binding.edit.addTextChangedListener {
binding.tvConfirm.isEnabled = it.toString().isNotEmpty()
binding.tvErrorTip.visibility = View.GONE
}
binding.tvCancel.setOnClickListener {
dialog.dismiss()
cancelAction?.invoke()
}
binding.tvConfirm.setOnClickListener {
val pwd = binding.edit.text.toString()
if (!isCheckPwd) {
//加锁逻辑
if (state == 0) {
PdfBoxUtils.setPassword(path, pwd, pwd)
toast("Success Encryption")
encryptionAction?.invoke()
dialog.dismiss()
firstDialog?.dismiss()
}
//解锁逻辑
if (state == 1) {
val result = checkPwd(path, pwd, uri)
LogEx.logDebug("checkPwd", "result=$result")
if (result) {
PdfBoxUtils.clearPassword(path, pwd)
toast("clear Encryption")
encryptionAction?.invoke()
dialog.dismiss()
firstDialog?.dismiss()
} else {
binding.tvErrorTip.visibility = View.VISIBLE
}
}
} else {
//验证密码逻辑
val result = checkPwd(path, pwd, uri)
if (!result) {
binding.tvErrorTip.visibility = View.VISIBLE
return@setOnClickListener
}
dialog.dismiss()
firstDialog?.dismiss()
verificationAction?.invoke(pwd)
}
}
binding.ivEye.setOnClickListener {
if (binding.edit.transformationMethod == null) {
// 隐藏密码
binding.edit.transformationMethod = PasswordTransformationMethod()
binding.ivEye.setImageResource(R.mipmap.weishuru)
} else {
// 显示密码
binding.edit.transformationMethod = null
binding.ivEye.setImageResource(R.mipmap.yishuru)
}
}
}
}
\ No newline at end of file
package com.base.pdfoneread.ui.views
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.airbnb.lottie.LottieAnimationView
class XmlLottieAnimationView : LottieAnimationView {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun draw(canvas: Canvas) {
try {
super.draw(canvas)
} catch (e: Exception) {
}
}
override fun playAnimation() {
super.playAnimation()
}
}
\ No newline at end of file
package com.base.pdfoneread.utils
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.core.content.FileProvider
import com.base.pdfoneread.R
import com.base.pdfoneread.bean.DocumentBean
import com.base.pdfoneread.bean.DocumentBean.Companion.TYPE_PDF
import java.io.File
object IntentShareUtils {
fun Context.documentShare(documentBean: DocumentBean) {
val uri = FileProvider.getUriForFile(
this, this.packageName + ".provider", File(documentBean.path)
)
var intent: Intent? = null
var desc = getString(R.string.share_pdf)
if (documentBean.type == DocumentBean.TYPE_PPT) {
intent = sharePptIntent(uri)
desc = getString(R.string.share_ppt)
}
if (documentBean.type == DocumentBean.TYPE_WORD) {
intent = shareWordIntent(uri)
desc = getString(R.string.share_word)
}
if (documentBean.type == DocumentBean.TYPE_EXCEL) {
intent = shareExcelIntent(uri)
desc = getString(R.string.share_excel)
}
intent?.let { startActivity(Intent.createChooser(it, desc)) }
}
fun sharePdfIntent(uri: Uri): Intent {
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, uri)
type = "application/pdf"
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 授权临时权限
}
return shareIntent
}
fun sharePptIntent(uri: Uri): Intent {
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, uri)
type = "application/vnd.ms-powerpoint"
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 授权临时权限
}
return shareIntent
}
fun shareWordIntent(uri: Uri): Intent {
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, uri)
type = "application/msword"
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 授权临时权限
}
return shareIntent
}
fun shareExcelIntent(uri: Uri): Intent {
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, uri)
type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 授权临时权限
}
return shareIntent
}
fun sharePdfPrintIntent(uri: Uri): Intent {
// 创建打印的 Intent
val intent = Intent(Intent.ACTION_SEND)
intent.setDataAndType(uri, "application/pdf")
// 启动打印服务
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
return intent
}
fun Context.shareMutDocuments(
type: String, uris: ArrayList<Uri>
) {
var desc = "Share PDF files"
val intent = when (type) {
TYPE_PDF -> {
shareMutPdfIntent(uris)
}
else -> shareMutPdfIntent(uris)
}
val chooserIntent = Intent.createChooser(intent, desc)
startActivity(chooserIntent)
}
fun shareMutPdfIntent(uris: ArrayList<Uri>): Intent {
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND_MULTIPLE
type = "application/pdf"
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 授权临时权限
putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
}
return shareIntent
}
}
\ No newline at end of file
package com.base.pdfoneread.utils
import android.annotation.SuppressLint
import android.content.Context
import android.content.Context.INPUT_METHOD_SERVICE
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
object KeyBoardUtils {
@SuppressLint("ServiceCast")
fun Context.hideKeyboard(editText: EditText) {
editText.clearFocus()
val imm = this.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editText.windowToken, 0)
}
@SuppressLint("ServiceCast")
fun Context.showKeyBoard(editText: EditText) {
editText.requestFocus()
val imm = this.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager?
imm?.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
}
}
\ No newline at end of file
......@@ -44,6 +44,10 @@ object KotlinExt {
return SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH).format(this)
}
fun Long.toFormatTime6(): String {
return SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.ENGLISH).format(this)
}
fun Long.toFormatMinute(): String {
return SimpleDateFormat("mm", Locale.ENGLISH).format(this)
}
......
package com.base.pdfoneread.utils
import android.text.InputFilter
import android.text.Spanned
class NumberRangeFilter(private val min: Int, private val max: Int) : InputFilter {
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int): CharSequence? {
try {
val input = dest.subSequence(0, dstart).toString() + source.toString() + dest.subSequence(dend, dest.length)
val numericValue = input.toIntOrNull()
if (numericValue != null && numericValue in min..max) {
return null // 允许输入
}
} catch (nfe: NumberFormatException) {
// 如果输入不是数字,则忽略
}
return "" // 拒绝输入
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#00B8DE" />
<corners android:radius="16dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#00B8DE"/>
<corners android:radius="4dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="5dp" />
<solid android:color="#54585B" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#7FDCEE"/>
<corners android:radius="10dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#9699A2" />
<corners android:radius="4dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#B3000000" />
<corners android:radius="10dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F1F2F6"/>
<corners android:radius="10dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F3F3F3" />
<corners
android:topLeftRadius="25dp"
android:topRightRadius="25dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="10dp" />
<solid android:color="#F8F9FE" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FB2B39" />
<corners android:radius="10dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_00b8de_10" android:state_enabled="true" />
<item android:drawable="@drawable/bg_7fdcee_10" android:state_enabled="false" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_stoke_00bbde_5" android:state_selected="true"/>
<item android:drawable="@drawable/bg_stoke_cfcfcf_5" android:state_selected="false"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/bg_00b8de_4"/>
<item android:state_selected="false" android:drawable="@drawable/bg_9699a2_4"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/pdf_k_s" android:state_selected="true" />
<item android:drawable="@mipmap/pdf_k1" android:state_selected="false" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="1dp"
android:color="#00B8DE" />
<corners android:radius="5dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="0.5dp"
android:color="#BABABA" />
<corners android:radius="10dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="1dp"
android:color="#CFCFCF" />
<corners android:radius="5dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 设置背景色 -->
<item android:id="@android:id/background">
<shape>
<solid android:color="#3300B8DE" />
<corners android:radius="2.5dp" />
</shape>
</item>
<!-- 设置进度条颜色 -->
<!-- <item android:id="@android:id/progress">-->
<!-- <scale android:scaleWidth="100%">-->
<!-- <clip>-->
<!-- <shape>-->
<!-- <corners android:radius="2.5dp" />-->
<!-- <solid android:color="#00B8DE" />-->
<!-- </shape>-->
<!-- </clip>-->
<!-- </scale>-->
<!-- </item>-->
</layer-list>
\ No newline at end of file
......@@ -181,4 +181,29 @@
</LinearLayout>
<LinearLayout
android:id="@+id/fl_banner"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_bottom">
<View
android:layout_width="wrap_content"
android:layout_height="1.5dp"
android:background="#D2D2D2" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="2dp"
android:src="@mipmap/zhanweitu2"
android:tag="zhanweitu"
tools:ignore="ContentDescription" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/tu_loading"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.35"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="76dp"
android:text="@string/splitting_pdf_please_wait"
android:textColor="#333333"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="@id/iv"
app:layout_constraintStart_toStartOf="@id/iv"
app:layout_constraintTop_toBottomOf="@id/iv"
tools:ignore="HardcodedText" />
<ProgressBar
android:id="@+id/progressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="16sp"
android:layout_marginHorizontal="56dp"
android:layout_marginTop="19dp"
android:max="100"
android:progressDrawable="@drawable/progress_bg_pdf_loading"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_desc" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="60dp"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="@+id/fl_fanhui"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="15dp"
android:src="@mipmap/pdf_left"
tools:ignore="ContentDescription" />
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/merge_pdf"
android:textColor="@color/black"
android:textSize="19sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:text="@string/add"
android:textColor="#00B8DE"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@id/tv_btn_next"
app:layout_constraintTop_toBottomOf="@id/cl_top">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_pdf_merge" />
</FrameLayout>
<TextView
android:id="@+id/tv_btn_next"
android:layout_width="338dp"
android:layout_height="48dp"
android:layout_marginBottom="24dp"
android:background="@drawable/bg_selector_btn"
android:enabled="false"
android:gravity="center"
android:text="@string/merge"
android:textColor="@color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top"
android:layout_width="match_parent"
android:layout_height="60dp"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="@+id/fl_fanhui"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tv_select_tip"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="15dp"
android:src="@mipmap/pdf_left"
tools:ignore="ContentDescription" />
</FrameLayout>
<TextView
android:id="@+id/tv_select_tip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="19sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText"
tools:text="1 item has been selected" />
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@id/tv_btn_next"
app:layout_constraintTop_toBottomOf="@id/cl_top">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_document" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<LinearLayout
android:id="@+id/ll_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="60dp"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables,UselessParent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/no_empty"
android:layout_gravity="center_horizontal"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="Empty"
android:textColor="#B1B4B9"
android:textSize="16sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</FrameLayout>
<TextView
android:id="@+id/tv_btn_next"
android:layout_width="338dp"
android:layout_height="48dp"
android:layout_marginBottom="24dp"
android:background="@drawable/bg_selector_btn"
android:enabled="false"
android:gravity="center"
android:text="@string/next"
android:textColor="@color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<FrameLayout
android:id="@+id/fl_fanhui"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pdf_left"
tools:ignore="ContentDescription" />
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13dp"
android:text="@string/split_pdf"
android:textColor="@color/black"
android:textSize="19sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/iv_selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="34dp"
android:src="@drawable/bg_selector_select"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,ImageContrastCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="3"
tools:ignore="SpeakableTextPresentCheck"
tools:listitem="@layout/item_pdf_pager_split" />
<TextView
android:id="@+id/tv_btn_split"
android:layout_width="338dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:layout_marginBottom="35dp"
android:background="@drawable/bg_selector_btn"
android:enabled="false"
android:gravity="center"
android:text="@string/split"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_f3f3f3_tlr25"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="65dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:includeFontPadding="false"
android:text="@string/delete"
android:textColor="#333333"
android:textSize="17sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/fl">
<TextView
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="32dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:paddingHorizontal="20dp"
android:singleLine="true"
android:text="@string/are_you_sure_you_want_to_delete_it"
android:textColor="#333333"
android:textSize="18sp"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="26dp"
android:layout_marginBottom="20dp">
<TextView
android:id="@+id/tv_cancel"
android:layout_width="163dp"
android:layout_height="48dp"
android:background="@drawable/bg_f1f2f6_10"
android:gravity="center"
android:text="@string/cancel"
android:textColor="#505050"
android:textSize="18sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_delete"
android:layout_width="163dp"
android:layout_height="48dp"
android:layout_marginStart="14dp"
android:background="@drawable/bg_fb2b39_10"
android:gravity="center"
android:text="@string/delete"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="345dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_ffffff_15"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl"
android:layout_width="match_parent"
android:layout_height="65dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="@string/info"
android:textColor="#333333"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="85dp"
android:background="?android:selectableItemBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:ignore="UselessParent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:includeFontPadding="false"
android:text="@string/name"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="16dp"
android:includeFontPadding="false"
android:textColor="@color/black"
android:textSize="14sp"
tools:text="DEMO.pdf" />
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="85dp"
android:background="?android:selectableItemBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:ignore="UselessParent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:includeFontPadding="false"
android:text="File Size"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="2"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="14sp"
tools:text="666.66 KB" />
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="85dp"
android:background="?android:selectableItemBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:ignore="UselessParent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:includeFontPadding="false"
android:text="Storage Path"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_path"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="14sp"
tools:text="/data/user/0/com.pdfviewer.scanner/files/ demo/DEMO.pdf" />
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="85dp"
android:background="?android:selectableItemBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:ignore="UselessParent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:includeFontPadding="false"
android:text="@string/last_modified"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_last_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="2"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="14sp"
tools:text="2024-09-10 13:58:00" />
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="85dp"
android:background="?android:selectableItemBackground">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:ignore="UselessParent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:includeFontPadding="false"
android:text="@string/last_viewed"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_last_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:maxLines="2"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="14sp"
tools:text="2024-09-10 13:58:00" />
</LinearLayout>
</FrameLayout>
<TextView
android:id="@+id/tv_btn_ok"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:layout_marginHorizontal="20dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="25dp"
android:background="@drawable/bg_00b8de_10"
android:gravity="center"
android:text="OK"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_f3f3f3_tlr25"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="65dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:includeFontPadding="false"
android:text="@string/rename"
android:textColor="#333333"
android:textSize="17sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/fl">
<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="32dp"
android:background="@drawable/bg_stoke_bababa_10"
android:ellipsize="end"
android:gravity="center_vertical"
android:paddingHorizontal="20dp"
android:singleLine="true"
android:text="DEMO.pdf"
android:textColor="#333333"
android:textSize="18sp"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="26dp"
android:layout_marginBottom="20dp">
<TextView
android:id="@+id/tv_cancel"
android:layout_width="163dp"
android:layout_height="48dp"
android:background="@drawable/bg_f1f2f6_10"
android:gravity="center"
android:text="@string/cancel"
android:textColor="#505050"
android:textSize="18sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_ok"
android:layout_width="163dp"
android:layout_height="48dp"
android:layout_marginStart="14dp"
android:background="@drawable/bg_selector_btn"
android:gravity="center"
android:text="@string/ok"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_f3f3f3_tlr25"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="65dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:includeFontPadding="false"
android:text="@string/page_number"
android:textColor="#333333"
android:textSize="17sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/fl"
app:layout_constraintVertical_bias="0.0"
tools:layout_editor_absoluteX="35dp">
<EditText
android:maxLength="1"
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="32dp"
android:background="@drawable/bg_stoke_bababa_10"
android:ellipsize="end"
android:gravity="center_vertical"
android:hint="1 - 10"
android:inputType="number"
android:paddingHorizontal="20dp"
android:singleLine="true"
android:textColor="#333333"
android:textColorHint="#C0C0C0"
android:textSize="18sp"
tools:ignore="Autofill,HardcodedText,LabelFor,TextFields" />
<TextView
android:id="@+id/tv_ok"
android:layout_width="338dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="26dp"
android:layout_marginBottom="20dp"
android:background="@drawable/bg_selector_btn"
android:enabled="false"
android:gravity="center"
android:text="@string/ok"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
......@@ -14,6 +15,7 @@
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_document" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
......
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fl_border"
android:layout_width="53dp"
android:layout_height="75dp"
android:layout_margin="4dp"
android:background="@drawable/bg_selector_pager_border">
<ImageView
android:id="@+id/iv_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:importantForAccessibility="no"
android:scaleType="fitXY" />
<TextView
android:id="@+id/tv_pager_index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="4dp"
android:background="@drawable/bg_selector_pager_text"
android:padding="1dp"
android:text="1"
android:textSize="8sp"
tools:ignore="HardcodedText,SmallSp" />
</FrameLayout>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment