From 587636c7a57645daf5f77e1a20c83117c8598401 Mon Sep 17 00:00:00 2001 From: litingting Date: Fri, 17 Oct 2025 18:07:02 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=A6=E6=83=85=E5=88=A0=E9=99=A4=E5=92=8C?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=E5=90=8E=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=BB=A7=E7=BB=AD=E8=BF=9B=E8=A1=8C=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=88=96=E8=80=85=E6=81=A2=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/BaseIngDialogFragment.kt | 11 +- .../file/filerecovery/base/NewBaseAdapter.kt | 2 +- .../photo/ConfirmDeleteDialogFragment.kt | 45 ++++ .../photo/DeletingDialogFragment.kt | 2 +- .../photo/PhotoDisplayDateAdapter.kt | 15 +- .../photo/PhotoDisplayDateChildAdapter.kt | 26 +- .../filerecovery/photo/PhotoInfoActivity.kt | 44 +++- .../photo/PhotoSortingActivity.kt | 241 +++++++++++++----- .../photo/RecoverOrDeleteManager.kt | 114 +++++++++ .../photo/RecoveringDialogFragment.kt | 2 +- .../success/RecoverySuccessActivity.kt | 77 +++++- .../video/file/filerecovery/utils/Common.kt | 20 +- .../filerecovery/utils/ExtendFunctions.kt | 10 + .../file/filerecovery/utils/ScanRepository.kt | 29 ++- app/src/main/res/drawable/icon_back_home.png | Bin 0 -> 3040 bytes .../main/res/layout/activity_photo_info.xml | 39 +-- .../activity_recover_or_deleted_success.xml | 71 ++++-- app/src/main/res/layout/common_bottom_btn.xml | 8 +- app/src/main/res/layout/dialog_delete.xml | 74 ++++++ app/src/main/res/values/strings.xml | 3 + 20 files changed, 652 insertions(+), 181 deletions(-) create mode 100644 app/src/main/java/com/ux/video/file/filerecovery/photo/ConfirmDeleteDialogFragment.kt create mode 100644 app/src/main/java/com/ux/video/file/filerecovery/photo/RecoverOrDeleteManager.kt create mode 100644 app/src/main/res/drawable/icon_back_home.png create mode 100644 app/src/main/res/layout/dialog_delete.xml diff --git a/app/src/main/java/com/ux/video/file/filerecovery/base/BaseIngDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/base/BaseIngDialogFragment.kt index 8fa73dd..6e4a9ae 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/base/BaseIngDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/base/BaseIngDialogFragment.kt @@ -13,13 +13,16 @@ import androidx.fragment.app.DialogFragment import com.ux.video.file.filerecovery.databinding.DialogRecoveringBinding -abstract class BaseIngDialogFragment(var total: Int, var complete: () -> Unit) : DialogFragment() { - +abstract class BaseIngDialogFragment() : DialogFragment() { + var total: Int = 0 + var completeListener: ((number: Int) -> Unit)? = null private lateinit var binding: DialogRecoveringBinding override fun onStart() { super.onStart() + dialog?.setCanceledOnTouchOutside(false) + isCancelable = false dialog?.window?.apply { setLayout( ViewGroup.LayoutParams.MATCH_PARENT, @@ -42,7 +45,7 @@ abstract class BaseIngDialogFragment(var total: Int, var complete: () -> Unit) : object : CountDownTimer(defaultTimer, 200) { override fun onFinish() { progressBar.progress = 100 - complete.invoke() + completeListener?.invoke(total) } override fun onTick(millisUntilFinished: Long) { @@ -75,7 +78,7 @@ abstract class BaseIngDialogFragment(var total: Int, var complete: () -> Unit) : binding.progressBar.progress = progress if (progress == 100) { - complete.invoke() + completeListener?.invoke(number) } } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/base/NewBaseAdapter.kt b/app/src/main/java/com/ux/video/file/filerecovery/base/NewBaseAdapter.kt index 2021620..721a7d4 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/base/NewBaseAdapter.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/base/NewBaseAdapter.kt @@ -24,7 +24,7 @@ abstract class NewBaseAdapter( items?.let { data.addAll(it) } notifyDataSetChanged() } - + fun getCurrentData() = data override fun getItemCount(): Int = data.size override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/ConfirmDeleteDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/ConfirmDeleteDialogFragment.kt new file mode 100644 index 0000000..ef0dcc7 --- /dev/null +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/ConfirmDeleteDialogFragment.kt @@ -0,0 +1,45 @@ +package com.ux.video.file.filerecovery.photo + +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.graphics.drawable.toDrawable +import androidx.fragment.app.DialogFragment +import com.ux.video.file.filerecovery.databinding.DialogDeleteBinding + + +/** + * 删除确认弹窗 + */ +class ConfirmDeleteDialogFragment() : DialogFragment() { + + var onClickDelete: (() -> Unit)? = null + private lateinit var binding: DialogDeleteBinding + override fun onStart() { + super.onStart() + dialog?.window?.apply { + setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) + } + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DialogDeleteBinding.inflate(inflater) + binding.run { + tvCancel.setOnClickListener { dismiss() } + tvDelete.setOnClickListener { + onClickDelete?.invoke() + dismiss() + } + } + return binding.root + } +} diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/DeletingDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/DeletingDialogFragment.kt index 67c2305..82d3ee6 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/photo/DeletingDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/DeletingDialogFragment.kt @@ -8,7 +8,7 @@ import com.ux.video.file.filerecovery.databinding.DialogRecoveringBinding /** * 删除中弹窗 */ -class DeletingDialogFragment(total: Int, complete:()-> Unit) : BaseIngDialogFragment(total,complete) { +class DeletingDialogFragment() : BaseIngDialogFragment() { override fun initUi(binding: DialogRecoveringBinding) { binding.run { diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateAdapter.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateAdapter.kt index 0e975cc..20420bd 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateAdapter.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateAdapter.kt @@ -25,7 +25,7 @@ class PhotoDisplayDateAdapter( private var allSelected: Boolean? = null -// private var hideThumbnails = false + override fun getViewBinding(parent: ViewGroup): PhotoDisplayDateAdapterBinding = PhotoDisplayDateAdapterBinding.inflate( LayoutInflater.from(parent.context), @@ -33,10 +33,7 @@ class PhotoDisplayDateAdapter( false ) - fun updateHideThumbnails(isChecked: Boolean) { -// hideThumbnails = isChecked - notifyDataSetChanged() - } + /** * 返回所有嵌套的数据量总数 @@ -97,14 +94,6 @@ class PhotoDisplayDateAdapter( },clickItem ).apply { setData(files) } -// if (hideThumbnails && files.filter { !it.isThumbnail }.isEmpty()) { -// holder.vb.root.isVisible = false -// return -// }else{ -// holder.vb.root.isVisible = true -// childAdapter.updateHideThumbnails(hideThumbnails) -// } - allSelected?.let { childAdapter.setAllSelected(it) } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateChildAdapter.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateChildAdapter.kt index b4ae266..30b3bfd 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateChildAdapter.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoDisplayDateChildAdapter.kt @@ -43,27 +43,16 @@ class PhotoDisplayDateChildAdapter( ) : NewBaseAdapter(mContext) { -// private var hideThumbnails: Boolean? = null + //日期组某一天的数据选择状态维护 val dateSelectedMap = mutableSetOf() - //实际显示数据集合(包含隐藏的缩略图) -// val visibleList = data.toMutableSet() companion object { private const val TYPE_TWO = 2 private const val TYPE_THREE = 3 private const val TYPE_FOUR = 4 } - -// fun getVisibleList() = visibleList - - fun updateHideThumbnails(isChecked: Boolean){ -// hideThumbnails = isChecked - notifyDataSetChanged() - hideThumbnailsUpdate.invoke(getVisibleCount(dateSelectedMap.toMutableList(),isChecked) == getVisibleCount(data,isChecked)) - } - fun setAllSelected(isAdd: Boolean) { data.forEach { addOrRemove(it, isAdd) @@ -132,12 +121,12 @@ class PhotoDisplayDateChildAdapter( when (holder) { is TwoHolder -> holder.vb.run { -// root.isVisible = !(hideThumbnails == true && item.isThumbnail) + initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item) } is ThreeHolder -> holder.vb.run { -// root.isVisible = !(hideThumbnails == true && item.isThumbnail) + initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item) } } @@ -218,16 +207,11 @@ class PhotoDisplayDateChildAdapter( dateSelectedMap.remove(resultPhotosFiles) } onSelectedUpdate.invoke(resultPhotosFiles, boolean, dateSelectedMap.size == data.size) -// updateSelected(resultPhotosFiles,boolean) - } - - private fun updateSelected(resultPhotosFiles: ResultPhotosFiles,boolean: Boolean){ -// hideThumbnails?.let { -// onSelectedUpdate.invoke(resultPhotosFiles, boolean, getVisibleCount(dateSelectedMap.toMutableList(),it) == getVisibleCount(data,it)) -// } } + + fun getVisibleCount(list: MutableList = data, hideThumbnails: Boolean): Int { if(hideThumbnails){ return list.filter { !it.isThumbnail }.size diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoInfoActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoInfoActivity.kt index 88d31cb..f767c95 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoInfoActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoInfoActivity.kt @@ -1,5 +1,6 @@ package com.ux.video.file.filerecovery.photo +import android.content.Intent import android.graphics.drawable.Drawable import android.os.Build import android.os.Bundle @@ -8,6 +9,7 @@ import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException @@ -20,6 +22,8 @@ import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.base.BaseActivity import com.ux.video.file.filerecovery.databinding.ActivityPhotoInfoBinding import com.ux.video.file.filerecovery.databinding.ActivityPhotoSortingBinding +import com.ux.video.file.filerecovery.photo.PhotoSortingActivity +import com.ux.video.file.filerecovery.success.RecoverySuccessActivity import com.ux.video.file.filerecovery.utils.Common import com.ux.video.file.filerecovery.utils.ExtendFunctions.dpToPx import com.ux.video.file.filerecovery.utils.ScanManager @@ -43,17 +47,17 @@ class PhotoInfoActivity : BaseActivity() { @Suppress("DEPRECATION") intent.getParcelableExtra("MY_KEY") } - binding.run { - myData?.let { + imageViewBack.setOnClickListener { finish() } + myData?.let { resultPhotosFiles-> - tvName.text = it.name - tvPath.text = it.path - tvDate.text = Common.getFormatDate(it.lastModified) - tvResolution.text = it.resolution + tvName.text = resultPhotosFiles.name + tvPath.text = resultPhotosFiles.path + tvDate.text = Common.getFormatDate(resultPhotosFiles.lastModified) + tvResolution.text = resultPhotosFiles.resolution Glide.with(this@PhotoInfoActivity) - .load(it.targetFile) + .load(resultPhotosFiles.targetFile) .apply( RequestOptions() .transform( @@ -84,9 +88,33 @@ class PhotoInfoActivity : BaseActivity() { }) .into(image) + + layoutBottom.tvLeft.run { + text = resources.getString(R.string.delete) + setOnClickListener { + RecoverOrDeleteManager.showConfirmDeleteDialog(true,supportFragmentManager,lifecycleScope,setOf(resultPhotosFiles)){count-> + complete(count,1) + } + } + } + + layoutBottom.tvRight.run { + text = resources.getString(R.string.recover) + setOnClickListener { + RecoverOrDeleteManager.showRecoveringDialog(supportFragmentManager,lifecycleScope,setOf(resultPhotosFiles)){count-> + complete(count,0) + } + } + } } } + } - + private fun complete(number: Int,type: Int) { + finish() + startActivity(Intent(this@PhotoInfoActivity, RecoverySuccessActivity::class.java).apply { + putExtra(RecoverySuccessActivity.KEY_SUCCESS_COUNT,number) + putExtra(RecoverySuccessActivity.KEY_SUCCESS_TYPE,type) + }) } } \ No newline at end of file diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoSortingActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoSortingActivity.kt index 4b6165d..e5c5439 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoSortingActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/PhotoSortingActivity.kt @@ -23,12 +23,15 @@ import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterWithinDateRang import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterWithinDateRangeList import com.ux.video.file.filerecovery.utils.ExtendFunctions.getParcelableArrayListExtraCompat import com.ux.video.file.filerecovery.utils.ExtendFunctions.mbToBytes +import com.ux.video.file.filerecovery.utils.ExtendFunctions.removeItem import com.ux.video.file.filerecovery.utils.GridSpacingItemDecoration import com.ux.video.file.filerecovery.utils.ScanManager import com.ux.video.file.filerecovery.utils.ScanManager.copySelectedFilesAsync import com.ux.video.file.filerecovery.utils.ScanManager.deleteFilesAsync import com.ux.video.file.filerecovery.utils.ScanRepository +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.util.Date class PhotoSortingActivity : BaseActivity() { @@ -61,9 +64,6 @@ class PhotoSortingActivity : BaseActivity() { //文件大小排序使用的适配器 private var sizeSortAdapter: PhotoDisplayDateChildAdapter? = null - private var dialogRecovering: RecoveringDialogFragment? = null - - private var dialogDeleting: DeletingDialogFragment? = null private var dialogCustomerDateStart: DatePickerDialogFragment? = null private var dialogCustomerDateEnd: DatePickerDialogFragment? = null @@ -92,7 +92,7 @@ class PhotoSortingActivity : BaseActivity() { private lateinit var sortedByDatePositive: List>> //最新显示的数据集合(包含缩略图 ,只保存当前筛选后或者排序后显示的数据,不受switch切换影响) - private var currentDateList: List>>? = null + private var currentDateList: List>>? = null private var currentSizeList: List? = null //选中的所有数据集合(实际选中) @@ -180,6 +180,7 @@ class PhotoSortingActivity : BaseActivity() { resetCurrentDateList(sortByDateReverse) } setDateAdapter() + setSingleDelete() setFilter() binding.run { imageViewBack.setOnClickListener { finish() } @@ -188,7 +189,7 @@ class PhotoSortingActivity : BaseActivity() { is PhotoDisplayDateAdapter -> { lifecycleScope.launch { dateAdapter?.run { - initGetCurrentDateList().let { list-> + initGetCurrentDateList().let { list -> val filterThumbnailsAsync = if (isChecked) list.filterThumbnailsAsync() else list setData(filterThumbnailsAsync) @@ -219,36 +220,24 @@ class PhotoSortingActivity : BaseActivity() { } tvRecover.setOnClickListener { - showRecoveringDialog() - lifecycleScope.copySelectedFilesAsync( - selectedSet = filterSelectedSetList, - folder = Common.recoveryPhotoDir, - onProgress = { currentCounts: Int, fileName: String, success: Boolean -> - ScanManager.showLog( - "--------恢复图片 ", - "----------${currentCounts} ${fileName}" - ) - dialogRecovering?.updateProgress(currentCounts) - - }) { counts -> - dialogRecovering?.updateProgress(counts) - ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") +// showRecoveringDialog() + RecoverOrDeleteManager.showRecoveringDialog( + supportFragmentManager, + lifecycleScope, + filterSelectedSetList + ) { count -> + complete(count, 0) } } tvDelete.setOnClickListener { - showDeletingDialog() - lifecycleScope.deleteFilesAsync( - selectedSet = filterSelectedSetList, - onProgress = { currentCounts: Int, path: String, success: Boolean -> - ScanManager.showLog( - "--------删除图片 ", - "----------${currentCounts} ${path}" - ) - dialogDeleting?.updateProgress(currentCounts) - }) { counts -> - dialogDeleting?.updateProgress(counts) - ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") +// showConfirmDeleteDialog() + RecoverOrDeleteManager.showConfirmDeleteDialog( + fragmentManager = supportFragmentManager, + scope = lifecycleScope, + selectedSetList = filterSelectedSetList + ) { count -> + complete(count, 1) } } @@ -277,7 +266,8 @@ class PhotoSortingActivity : BaseActivity() { initGetCurrentDateList().let { val filterThumbnailsAsync = if (switchHideThumbnails.isChecked) it.filterThumbnailsAsync() else it - val sortByDayNewToOld = Common.getSortByDayNewToOld(filterThumbnailsAsync) + val sortByDayNewToOld = + Common.getSortByDayNewToOld(filterThumbnailsAsync) dateAdapter?.setData(sortByDayNewToOld) resetCurrentDateList(sortByDayNewToOld) } @@ -323,8 +313,28 @@ class PhotoSortingActivity : BaseActivity() { //全选按钮 只对当前显示的数据有效 tvSelectAll.setOnClickListener { it.isSelected = !it.isSelected - dateAdapter?.setAllSelected(it.isSelected) - sizeSortAdapter?.setAllSelected(it.isSelected) + when (binding.recyclerView.adapter) { + is PhotoDisplayDateAdapter -> { + dateAdapter?.setAllSelected(it.isSelected) + dateAdapter?.getCurrentData()?.let { + it as List>> + + if (it.size > 0) + Common.showLog("------------全选按钮 日期-${it.size} ${it[0].second[0].path}") + } + + } + is PhotoDisplayDateChildAdapter -> { + sizeSortAdapter?.setAllSelected(it.isSelected) + sizeSortAdapter?.getCurrentData()?.let { + it as List + if (it.size > 0) + Common.showLog("------------全选按钮 大小-${it.size} ${it[0].path}") + } + } + } + + } } @@ -339,14 +349,22 @@ class PhotoSortingActivity : BaseActivity() { when (binding.recyclerView.adapter) { is PhotoDisplayDateAdapter -> { val adapter = binding.recyclerView.adapter as PhotoDisplayDateAdapter - binding.tvSelectAll.isSelected = it == adapter.getTotalChildCount(false) + if (it > 0) { + binding.tvSelectAll.isSelected = it == adapter.getTotalChildCount(false) + } else { + binding.tvSelectAll.isSelected = false + } + } is PhotoDisplayDateChildAdapter -> { val adapter = binding.recyclerView.adapter as PhotoDisplayDateChildAdapter - binding.tvSelectAll.isSelected = - it == adapter.itemCount - + if (it > 0) { + binding.tvSelectAll.isSelected = + it == adapter.itemCount + } else { + binding.tvSelectAll.isSelected = false + } } } } @@ -358,19 +376,29 @@ class PhotoSortingActivity : BaseActivity() { currentSizeList = currentSizeList ?: currentDateList?.flatMap { it.second } return currentSizeList!! } - private fun resetCurrentSizeList(currentList: List) { + + private fun resetCurrentSizeList(currentList: List) { currentSizeList = currentList currentDateList = null + binding.tvThumbnailCounts.text = + getString(R.string.hide_thumbnails, currentList.filter { it.isThumbnail }.size) + } private fun initGetCurrentDateList(): List>> { currentDateList = currentDateList ?: Common.getSortByDayNewToOldInit(currentSizeList!!) return currentDateList!! } - private fun resetCurrentDateList(currentList: List>> ) { + + private fun resetCurrentDateList(currentList: List>>) { currentDateList = currentList currentSizeList = null + val totalSelectedCount = currentList.sumOf { pair -> + pair.second.filter { it.isThumbnail }.size + } + binding.tvThumbnailCounts.text = + getString(R.string.hide_thumbnails, totalSelectedCount) } @@ -649,11 +677,9 @@ class PhotoSortingActivity : BaseActivity() { } onPickerChooseListener = { selectedDate -> filterStartDate = selectedDate -// filterDatePopupWindows?.updateStartEndDate(start = selectedDate) Log.d("showStartDateDialog", "isFirst=${isNeedSetSelected}--------") showEndDateDialog(isNeedSetSelected, null) - } onClickCancel = { @@ -701,34 +727,115 @@ class PhotoSortingActivity : BaseActivity() { } - /** - * 显示恢复中弹窗 - */ - private fun showRecoveringDialog() { - dialogRecovering = - dialogRecovering ?: RecoveringDialogFragment(filterSelectedSetList.size) { - complete() - } - dialogRecovering?.show(supportFragmentManager, "") - } - - - /** - * 显示删除中弹窗 - */ - private fun showDeletingDialog() { - dialogDeleting = dialogDeleting ?: DeletingDialogFragment(filterSelectedSetList.size) { - complete() - } - dialogDeleting?.show(supportFragmentManager, "") - } /** * 删除或者恢复完成 + * @param type 0 恢复 1 删除 */ - private fun complete() { - dialogDeleting?.dismiss() - dialogRecovering?.dismiss() - startActivity(Intent(this@PhotoSortingActivity, RecoverySuccessActivity::class.java)) + private fun complete(number: Int, type: Int) { + startActivity(Intent(this@PhotoSortingActivity, RecoverySuccessActivity::class.java).apply { + putExtra(RecoverySuccessActivity.KEY_SUCCESS_COUNT, number) + putExtra(RecoverySuccessActivity.KEY_SUCCESS_TYPE, type) + }) + if (type == 1) { + lifecycleScope.launch { + val deferredResults = withContext(Dispatchers.Default) { + filterSelectedSetList.let { deletedData -> + //删除后,处理当前实际显示的数据 + val newSizeList = currentSizeList?.let { + Common.removeSelectedFromSizeList( + it, + deletedData + ) + } + val newDateList = currentDateList?.let { + Common.removeSelectedFromList(it, deletedData) + } + + //后续用于筛选的原始数据更新 + sortBySizeBigToSmall = + Common.removeSelectedFromSizeList(sortBySizeBigToSmall, deletedData) + sortBySizeSmallToBig = + Common.removeSelectedFromSizeList(sortBySizeSmallToBig, deletedData) + sortByDateReverse = + Common.removeSelectedFromList(sortByDateReverse, deletedData) + sortedByDatePositive = + Common.removeSelectedFromList(sortedByDatePositive, deletedData) + + + // 一次性返回结果 + mapOf( + "sizeList" to newSizeList, + "dateList" to newDateList, + ) + } + } + + withContext(Dispatchers.Main) { + //选中集合的更新 + viewModel.afterDeleted() + deferredResults["sizeList"]?.let { list -> + list as List + Common.showLog("---------更新 sizeList = ${list.size}") + sizeSortAdapter?.setData(list) + resetCurrentSizeList(list) + } + deferredResults["dateList"]?.let { list -> + list as List>> + Common.showLog("---------更新 dateList = ${list.size}") + dateAdapter?.setData(list) + resetCurrentDateList(list) + } + + } + } + } } + + private fun setSingleDelete() { + RecoverOrDeleteManager.setOnSingleDeleteCompleteListener { deletedData -> + lifecycleScope.launch { + val deferredResults = withContext(Dispatchers.Default) { + //删除后,处理当前实际显示的数据 + val newSizeList = currentSizeList?.let { + it.filterNot { it == deletedData } + } + val newDateList = currentDateList?.removeItem(deletedData) + + //后续用于筛选的原始数据更新 + sortBySizeBigToSmall = sortBySizeBigToSmall.filterNot { it == deletedData } + sortBySizeSmallToBig = sortBySizeSmallToBig.filterNot { it == deletedData } + sortByDateReverse = sortByDateReverse.removeItem(deletedData) + sortedByDatePositive = sortedByDatePositive.removeItem(deletedData) + + // 一次性返回结果 + mapOf( + "sizeList" to newSizeList, + "dateList" to newDateList, + ) + + } + + withContext(Dispatchers.Main) { + //选中集合的更新 + viewModel.afterSingleDeleted(deletedData) + deferredResults["sizeList"]?.let { list -> + list as List + Common.showLog("---------更新 sizeList = ${list.size}") + sizeSortAdapter?.setData(list) + resetCurrentSizeList(list) + } + deferredResults["dateList"]?.let { list -> + list as List>> + Common.showLog("---------更新 dateList = ${list.size}") + dateAdapter?.setData(list) + resetCurrentDateList(list) + } + + } + } + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoverOrDeleteManager.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoverOrDeleteManager.kt new file mode 100644 index 0000000..579f545 --- /dev/null +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoverOrDeleteManager.kt @@ -0,0 +1,114 @@ +package com.ux.video.file.filerecovery.photo + +import android.app.Activity +import androidx.fragment.app.FragmentManager + +import androidx.lifecycle.lifecycleScope +import com.ux.video.file.filerecovery.utils.Common +import com.ux.video.file.filerecovery.utils.ScanManager +import com.ux.video.file.filerecovery.utils.ScanManager.copySelectedFilesAsync +import com.ux.video.file.filerecovery.utils.ScanManager.deleteFilesAsync +import kotlinx.coroutines.CoroutineScope + +object RecoverOrDeleteManager { + + private var dialogRecovering: RecoveringDialogFragment? = null + + private var dialogDeleting: DeletingDialogFragment? = null + private var dialogConfirmDelete: ConfirmDeleteDialogFragment? = null + + //详情页面进行删除操作的监听 + private var onSingleDeletedCompleteListener: ((ResultPhotosFiles) -> Unit)? = null + + fun setOnSingleDeleteCompleteListener(listener: (ResultPhotosFiles) -> Unit) { + onSingleDeletedCompleteListener = listener + } + + + /** + * 显示恢复中弹窗 + */ + fun showRecoveringDialog( + fragmentManager: FragmentManager, + scope: CoroutineScope, + selectedSetList: Set, + onComplete: (number: Int) -> Unit + ) { + scope.copySelectedFilesAsync( + selectedSet = selectedSetList, + folder = Common.recoveryPhotoDir, + onProgress = { currentCounts: Int, fileName: String, success: Boolean -> + ScanManager.showLog("--------恢复图片 ", "----------${currentCounts} ${fileName}") + dialogRecovering?.updateProgress(currentCounts) + + }) { counts -> + dialogRecovering?.updateProgress(counts) + ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") + + } + dialogRecovering = dialogRecovering ?: RecoveringDialogFragment() + dialogRecovering?.run { + total = selectedSetList.size + completeListener = { number -> + onComplete(number) + dialogRecovering?.dismiss() + } + show(fragmentManager, "") + } + } + + /** + * 显示删除中弹窗 + */ + fun showConfirmDeleteDialog( + isInfoDelete: Boolean = false, + fragmentManager: FragmentManager, + scope: CoroutineScope, + selectedSetList: Set, + onComplete: (number: Int) -> Unit + ) { + dialogConfirmDelete = dialogConfirmDelete ?: ConfirmDeleteDialogFragment() + dialogConfirmDelete?.run { + onClickDelete = { + showDeletingDialog( + isInfoDelete, + fragmentManager, + scope, + selectedSetList, + onComplete + ) + } + show(fragmentManager, "") + } + } + + private fun showDeletingDialog( + isInfoDelete: Boolean = false, + fragmentManager: FragmentManager, + scope: CoroutineScope, + selectedSetList: Set, + onComplete: (number: Int) -> Unit + ) { + scope.deleteFilesAsync( + selectedSet = selectedSetList, + onProgress = { currentCounts: Int, path: String, success: Boolean -> + ScanManager.showLog("--------删除图片 ", "----------${currentCounts} ${path}") + dialogDeleting?.updateProgress(currentCounts) + }) { counts -> + dialogDeleting?.updateProgress(counts) + ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") + } + dialogDeleting = dialogDeleting ?: DeletingDialogFragment() + dialogDeleting?.run { + total = selectedSetList.size + completeListener = { number -> + dialogDeleting?.dismiss() + onComplete(number) + if (isInfoDelete && selectedSetList.size == 1) { + onSingleDeletedCompleteListener?.invoke(selectedSetList.first()) + } + } + show(fragmentManager, "") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoveringDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoveringDialogFragment.kt index 4b8385f..1a7ea4f 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoveringDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/photo/RecoveringDialogFragment.kt @@ -8,7 +8,7 @@ import com.ux.video.file.filerecovery.databinding.DialogRecoveringBinding /** * 恢复中弹窗 */ -class RecoveringDialogFragment(total: Int, complete:()-> Unit) : BaseIngDialogFragment(total,complete) { +class RecoveringDialogFragment() : BaseIngDialogFragment() { override fun initUi(binding: DialogRecoveringBinding) { binding.run { relativeLayout.setBackgroundResource(R.drawable.bg_rectangle_0048fd_top_20) diff --git a/app/src/main/java/com/ux/video/file/filerecovery/success/RecoverySuccessActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/success/RecoverySuccessActivity.kt index 00840db..94c0522 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/success/RecoverySuccessActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/success/RecoverySuccessActivity.kt @@ -3,16 +3,19 @@ package com.ux.video.file.filerecovery.success import android.content.Intent import android.os.Environment import android.view.LayoutInflater +import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.base.BaseActivity import com.ux.video.file.filerecovery.databinding.ActivityRecoverOrDeletedSuccessBinding import com.ux.video.file.filerecovery.databinding.ActivityScanningBinding +import com.ux.video.file.filerecovery.main.MainActivity import com.ux.video.file.filerecovery.main.ScanSelectTypeActivity.Companion.VALUE_AUDIO import com.ux.video.file.filerecovery.main.ScanSelectTypeActivity.Companion.VALUE_DOCUMENT import com.ux.video.file.filerecovery.main.ScanSelectTypeActivity.Companion.VALUE_PHOTO import com.ux.video.file.filerecovery.main.ScanSelectTypeActivity.Companion.VALUE_VIDEO import com.ux.video.file.filerecovery.result.ScanResultDisplayActivity +import com.ux.video.file.filerecovery.utils.Common import com.ux.video.file.filerecovery.utils.Common.KEY_SCAN_TYPE import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_audio import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_audio @@ -32,17 +35,87 @@ import kotlinx.coroutines.launch class RecoverySuccessActivity : BaseActivity() { companion object { -// val KEY_SCAN_TYPE = "scan_type" + val KEY_SUCCESS_TYPE = "success_type" + val KEY_SUCCESS_COUNT = "success_count" } private var scanType: Int = VALUE_SCAN_TYPE_photo + + //0 恢复成功 1 删除成功 + private var successType = 0 override fun inflateBinding(inflater: LayoutInflater): ActivityRecoverOrDeletedSuccessBinding = ActivityRecoverOrDeletedSuccessBinding.inflate(inflater) override fun initData() { super.initData() scanType = intent.getIntExtra(KEY_SCAN_TYPE, VALUE_SCAN_TYPE_photo) - binding.imageViewBack.setOnClickListener { finish() } + successType = intent.getIntExtra(KEY_SUCCESS_TYPE, 0) + val counts = intent.getIntExtra(KEY_SUCCESS_COUNT, 0) + + binding.run { + tvNumber.text = counts.toString() + bottomBtnRecoverLayout.run { + tvLeft.text = resources.getString(R.string.text_continue) + tvRight.text = resources.getString(R.string.view) + } + when (scanType) { + VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo -> tvFileType.text = + resources.getString(R.string.describe_photos) + + VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video -> tvFileType.text = + resources.getString(R.string.describe_videos) + + VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> tvFileType.text = + resources.getString(R.string.describe_audios) + + VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> tvFileType.text = + resources.getString(R.string.describe_documents) + } + when (successType) { + 0 -> { + imageCenter.setImageResource(R.drawable.image_recover_success) + tvNumber.setTextColor( + Common.getColorInt( + this@RecoverySuccessActivity, + R.color.main_text_blue + ) + ) + bottomBtnRecoverLayout.root.isVisible = true + tvContinue.isVisible = false + tvDescribe.text = resources.getString(R.string.recovered_success) + + bottomBtnRecoverLayout.tvLeft.setOnClickListener { finish()} + bottomBtnRecoverLayout.tvRight.setOnClickListener { + //todo 跳转到所有恢复文件页面 + } + + } + + 1 -> { + imageCenter.setImageResource(R.drawable.image_deleted_success) + tvNumber.setTextColor( + Common.getColorInt( + this@RecoverySuccessActivity, + R.color.dialog_shape_delete + ) + ) + bottomBtnRecoverLayout.root.isVisible = false + tvContinue.isVisible = true + tvDescribe.text = resources.getString(R.string.deleted_success) + tvContinue.setOnClickListener { finish()} + } + } + + imageViewBack.setOnClickListener { finish() } + imageBackHome.setOnClickListener { + val intent = Intent(this@RecoverySuccessActivity, MainActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP + startActivity(intent) + finish() + + } + } + } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/utils/Common.kt b/app/src/main/java/com/ux/video/file/filerecovery/utils/Common.kt index 67b6008..673230b 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/utils/Common.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/utils/Common.kt @@ -8,6 +8,7 @@ import android.util.Log import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat +import androidx.lifecycle.MutableLiveData import com.ux.video.file.filerecovery.App import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.photo.ResultPhotosFiles @@ -61,7 +62,6 @@ object Common { } - /** * 按照日期排序, 时间最早的排前面 升序 * @@ -247,6 +247,24 @@ object Common { } + fun removeSelectedFromList( + list: List>>, + selectedLiveData: Set + ): List>> { + return list.mapNotNull { (key, files) -> + val filtered = files.filterNot { it in selectedLiveData } + if (filtered.isNotEmpty()) key to filtered else null + } + } + + fun removeSelectedFromSizeList( + list: List, + selectedLiveData: Set + ): List { + return list.filterNot { it in selectedLiveData } + } + + fun getFormatDate(time: Long): String { return dateFormat.format(Date(time)) } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/utils/ExtendFunctions.kt b/app/src/main/java/com/ux/video/file/filerecovery/utils/ExtendFunctions.kt index 1b0502d..cb07409 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/utils/ExtendFunctions.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/utils/ExtendFunctions.kt @@ -206,4 +206,14 @@ object ExtendFunctions { } + fun List>>.removeItem( + target: ResultPhotosFiles + ): List>> { + return this.mapNotNull { (key, files) -> + val updatedFiles = files.filterNot { it == target } + if (updatedFiles.isNotEmpty()) key to updatedFiles else null + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanRepository.kt b/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanRepository.kt index 6ae0b43..6401932 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanRepository.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanRepository.kt @@ -31,7 +31,6 @@ class ScanRepository : ViewModel() { val current = _selectedLiveData.value?.toMutableSet() ?: mutableSetOf() val currentDisplay = _selectedDisplayLiveData.value?.toMutableSet() ?: mutableSetOf() resultPhotosFiles.let { - if (isAdd) { current.add(it) currentDisplay.add(it) @@ -60,6 +59,34 @@ class ScanRepository : ViewModel() { } + /** + * 删除操作完成过后,对选中集合进行更新 + */ + fun afterDeleted(){ + val selected = _selectedLiveData.value.orEmpty().toMutableSet() + val display = _selectedDisplayLiveData.value.orEmpty() + + selected.removeAll(display) + _selectedLiveData.value = selected + _selectedDisplayLiveData.value = emptySet() + + } + + /** + * 详情页删除完毕,移除删除掉的数据 + */ + fun afterSingleDeleted(deletedItem:ResultPhotosFiles){ + val selected = _selectedLiveData.value.orEmpty().toMutableSet() + val display = _selectedDisplayLiveData.value.orEmpty().toMutableSet() + + selected.remove(deletedItem) + display.remove(deletedItem) + _selectedLiveData.value = selected + _selectedDisplayLiveData.value = display + + } + + fun checkIsSelect(resultPhotosFiles: ResultPhotosFiles): Boolean { val current = _selectedLiveData.value diff --git a/app/src/main/res/drawable/icon_back_home.png b/app/src/main/res/drawable/icon_back_home.png new file mode 100644 index 0000000000000000000000000000000000000000..b24c4097ad1d097149e9016da87b99872f40ee6d GIT binary patch literal 3040 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 - - - - - - - - - - - - - - - - - - + app:layout_constraintBottom_toBottomOf="parent" /> - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_recover_or_deleted_success.xml b/app/src/main/res/layout/activity_recover_or_deleted_success.xml index 0ae4245..db8c407 100644 --- a/app/src/main/res/layout/activity_recover_or_deleted_success.xml +++ b/app/src/main/res/layout/activity_recover_or_deleted_success.xml @@ -32,6 +32,14 @@ android:textColor="@color/main_title" android:textSize="16sp" app:fontType="bold" /> + + - + android:baselineAligned="true" + android:orientation="horizontal"> + + + + + - + app:fontType="bold" + tools:text="Photo" /> + app:layout_constraintRight_toLeftOf="@id/bottom_btn_recover_layout" /> \ No newline at end of file diff --git a/app/src/main/res/layout/common_bottom_btn.xml b/app/src/main/res/layout/common_bottom_btn.xml index 26a1add..352620b 100644 --- a/app/src/main/res/layout/common_bottom_btn.xml +++ b/app/src/main/res/layout/common_bottom_btn.xml @@ -5,7 +5,7 @@ android:layout_height="wrap_content"> + app:layout_constraintRight_toLeftOf="@id/tv_right" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_delete.xml b/app/src/main/res/layout/dialog_delete.xml new file mode 100644 index 0000000..69eb4ca --- /dev/null +++ b/app/src/main/res/layout/dialog_delete.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b39116a..eb6b458 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,6 +75,9 @@ wait.. Continue Start date End date + The file(s) will be completely deleted and cannot be recovered. + Confirm delete? + View All