diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 16a6d89..78f70e2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,8 +19,8 @@ android { applicationId = "com.ux.video.file.filerecovery" minSdk = 24 targetSdk = 36 - versionCode = 2 - versionName = "1.1" + versionCode = 3 + versionName = "1.2" project.setProperty("archivesBaseName", "File Recovery Tool" + versionName + "(${versionCode})_$timestamp") testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f320dd5..96d350d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -74,6 +74,12 @@ -keep class kotlinx.android.parcel.Parcelize -keep class kotlin.Metadata { *; } +# 保留所有 Fragment 空构造函数 +-keep class * extends androidx.fragment.app.Fragment { + public (); +} + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b461008..5a9c269 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,9 +22,11 @@ tools:targetApi="31"> Unit)? = null - private lateinit var binding: DialogRecoveringBinding + private var _binding: DialogRecoveringBinding? = null + protected val binding get() = _binding!! + + + private var countDownTimer: CountDownTimer? = null + override fun onStart() { super.onStart() dialog?.setCanceledOnTouchOutside(false) @@ -40,15 +44,15 @@ abstract class BaseIngDialogFragment() : DialogFragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - binding = DialogRecoveringBinding.inflate(inflater) + _binding = DialogRecoveringBinding.inflate(inflater) initUi(binding) binding.run { if (total < 20) { val defaultTimer = 2000L - object : CountDownTimer(defaultTimer, 200) { + countDownTimer = object : CountDownTimer(defaultTimer, 200) { override fun onFinish() { progressBar.progress = 100 - completeListener?.invoke(total) +// completeListener?.invoke(total) } override fun onTick(millisUntilFinished: Long) { @@ -57,7 +61,8 @@ abstract class BaseIngDialogFragment() : DialogFragment() { progressBar.progress = i } - }.start() + }.also { it.start() } + } } @@ -69,6 +74,7 @@ abstract class BaseIngDialogFragment() : DialogFragment() { @SuppressLint("SetTextI18n") fun updateProgress(number: Int) { + val b = _binding ?: return binding.tvRecoverNumber.text = "${number}/" if (total < 20) { return @@ -81,9 +87,15 @@ abstract class BaseIngDialogFragment() : DialogFragment() { binding.progressBar.progress = progress if (progress == 100) { - completeListener?.invoke(number) +// completeListener?.invoke(number) } } + override fun onDestroyView() { + countDownTimer?.cancel() + countDownTimer = null + _binding = null + super.onDestroyView() + } } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/detail/DetailsActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/detail/DetailsActivity.kt index c1dc3e7..5a3ecee 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/detail/DetailsActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/detail/DetailsActivity.kt @@ -103,8 +103,7 @@ class DetailsActivity : BaseActivity() { myData?.let { myData -> RecoverOrDeleteManager.showConfirmDeleteDialog( true, - supportFragmentManager, - lifecycleScope, + this@DetailsActivity, setOf(myData) ) { count -> complete(count, 1) @@ -128,8 +127,7 @@ class DetailsActivity : BaseActivity() { text = getString(R.string.recover) setOnClickListener { RecoverOrDeleteManager.showRecoveringDialog( - supportFragmentManager, - lifecycleScope, + this@DetailsActivity, setOf(myData) ) { count -> complete(count, 0) diff --git a/app/src/main/java/com/ux/video/file/filerecovery/main/MainActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/main/MainActivity.kt index afcf59e..7425416 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/main/MainActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/main/MainActivity.kt @@ -19,6 +19,7 @@ import com.ux.video.file.filerecovery.databinding.ActivityMainBinding import com.ux.video.file.filerecovery.recovery.RecoveryActivity import com.ux.video.file.filerecovery.settings.SetupActivity import com.ux.video.file.filerecovery.utils.Common +import com.ux.video.file.filerecovery.utils.ExtendFunctions.safeShow import com.ux.video.file.filerecovery.utils.FileType import com.ux.video.file.filerecovery.utils.ScanManager @@ -168,7 +169,8 @@ class MainActivity : BaseActivity() { private fun requestPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - dialogPermission = dialogPermission ?: PermissionDialogFragment { + dialogPermission = dialogPermission ?: PermissionDialogFragment() + dialogPermission?.onClickAllow = { try { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply { @@ -181,7 +183,9 @@ class MainActivity : BaseActivity() { } isRequestPermission = true } - dialogPermission?.show(supportFragmentManager, "") + dialogPermission?.safeShow(supportFragmentManager, Common.TAG_DIALOG_PERMISSION) + + } else { requestPermissionLauncher.launch( arrayOf( diff --git a/app/src/main/java/com/ux/video/file/filerecovery/main/PermissionDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/main/PermissionDialogFragment.kt index fe27c4e..19536e9 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/main/PermissionDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/main/PermissionDialogFragment.kt @@ -10,9 +10,11 @@ import androidx.fragment.app.DialogFragment import com.ux.video.file.filerecovery.databinding.DialogPermissionBinding -class PermissionDialogFragment(val onClickAllow: () -> Unit) : DialogFragment() { +class PermissionDialogFragment() : DialogFragment() { private lateinit var binding: DialogPermissionBinding + + lateinit var onClickAllow: () -> Unit override fun onStart() { super.onStart() dialog?.window?.apply { @@ -27,7 +29,7 @@ class PermissionDialogFragment(val onClickAllow: () -> Unit) : DialogFragment() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { binding = DialogPermissionBinding.inflate(inflater) binding.run { cancel.setOnClickListener { dismiss() } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/recovery/ui/recoveryphoto/RecoveredFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/recovery/ui/recoveryphoto/RecoveredFragment.kt index 3c51e82..7a4b5b9 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/recovery/ui/recoveryphoto/RecoveredFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/recovery/ui/recoveryphoto/RecoveredFragment.kt @@ -250,8 +250,7 @@ class RecoveredFragment : BaseFragment() { layoutBottom.tvLeft.setOnClickListener { selectedList?.let { RecoverOrDeleteManager.showConfirmDeleteDialog( - fragmentManager = requireActivity().supportFragmentManager, - scope = lifecycleScope, + activity =requireActivity(), selectedSetList = it ) { count -> val removeSelectedFromSizeList = diff --git a/app/src/main/java/com/ux/video/file/filerecovery/result/ExitDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/result/ExitDialogFragment.kt index bdcf522..b17e690 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/result/ExitDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/result/ExitDialogFragment.kt @@ -11,9 +11,10 @@ import com.ux.video.file.filerecovery.databinding.DialogExitBinding import com.ux.video.file.filerecovery.databinding.DialogPermissionBinding -class ExitDialogFragment(val onClickExit: () -> Unit) : DialogFragment() { +class ExitDialogFragment() : DialogFragment() { private lateinit var binding: DialogExitBinding + lateinit var onClickExit: () -> Unit override fun onStart() { super.onStart() dialog?.window?.apply { diff --git a/app/src/main/java/com/ux/video/file/filerecovery/result/ScanResultDisplayActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/result/ScanResultDisplayActivity.kt index 3a2eaad..42aa066 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/result/ScanResultDisplayActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/result/ScanResultDisplayActivity.kt @@ -12,6 +12,7 @@ import com.ux.video.file.filerecovery.db.ResultData import com.ux.video.file.filerecovery.db.ResultDataFiles import com.ux.video.file.filerecovery.sort.SortingActivity import com.ux.video.file.filerecovery.utils.Common +import com.ux.video.file.filerecovery.utils.ExtendFunctions.safeShow import com.ux.video.file.filerecovery.utils.FileType import com.ux.video.file.filerecovery.utils.ScanType @@ -49,7 +50,7 @@ class ScanResultDisplayActivity : BaseActivity binding.run { val myAdapter = when (scanType.mediaType) { - FileType.AUDIO, FileType.DOCUMENT -> { + FileType.AUDIO, FileType.DOCUMENT -> { bottomLayout.setBackgroundResource(R.drawable.bg_rectangle_white_top_20) ScanResultDocumentsAudioAdapter( this@ScanResultDisplayActivity, @@ -70,7 +71,7 @@ class ScanResultDisplayActivity : BaseActivity } } - viewModel.scanData.observe(this@ScanResultDisplayActivity){ data-> + viewModel.scanData.observe(this@ScanResultDisplayActivity) { data -> list = data list.let { data -> textDirCount.text = data.size.toString() @@ -85,11 +86,15 @@ class ScanResultDisplayActivity : BaseActivity } } } + private fun dealExit() { - exitDialog = exitDialog ?: ExitDialogFragment { + exitDialog = exitDialog ?: ExitDialogFragment() + exitDialog?.onClickExit = { finish() } - exitDialog?.show(supportFragmentManager, "") + exitDialog?.safeShow(supportFragmentManager, Common.TAG_DIALOG_EXIT) + + } private fun setSelectTypeTitle(fileType: FileType) { @@ -100,7 +105,7 @@ class ScanResultDisplayActivity : BaseActivity textFileType.text = getString(R.string.text_photos) } - FileType.VIDEO-> { + FileType.VIDEO -> { title.text = getString(R.string.video_title) textFileType.text = getString(R.string.text_videos) } diff --git a/app/src/main/java/com/ux/video/file/filerecovery/sort/DeletingDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/sort/DeletingDialogFragment.kt index 71c42c3..ecf1524 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/sort/DeletingDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/sort/DeletingDialogFragment.kt @@ -1,15 +1,30 @@ package com.ux.video.file.filerecovery.sort +import androidx.fragment.app.FragmentManager import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.base.BaseIngDialogFragment import com.ux.video.file.filerecovery.databinding.DialogRecoveringBinding +import com.ux.video.file.filerecovery.utils.Common +import com.ux.video.file.filerecovery.utils.ExtendFunctions.safeShow /** * 删除中弹窗 */ class DeletingDialogFragment() : BaseIngDialogFragment() { + companion object { + val TAG = Common.TAG_DIALOG_DELETEING + fun show( + fm: FragmentManager, + total: Int + ): DeletingDialogFragment { + val dialog = DeletingDialogFragment() + dialog.total = total + dialog.safeShow(fm, TAG) + return dialog + } + } override fun initUi(binding: DialogRecoveringBinding) { binding.run { relativeLayout.setBackgroundResource(R.drawable.bg_rectangle_fdad00_top_20) diff --git a/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoverOrDeleteManager.kt b/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoverOrDeleteManager.kt index 954af7c..4c376be 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoverOrDeleteManager.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoverOrDeleteManager.kt @@ -1,10 +1,13 @@ package com.ux.video.file.filerecovery.sort +import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager +import androidx.lifecycle.LifecycleOwner import com.ux.video.file.filerecovery.db.ObjectBoxManager import com.ux.video.file.filerecovery.db.ResultDataFiles import com.ux.video.file.filerecovery.utils.Common +import com.ux.video.file.filerecovery.utils.ExtendFunctions.safeShow 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 @@ -12,9 +15,9 @@ import kotlinx.coroutines.CoroutineScope object RecoverOrDeleteManager { - private var dialogRecovering: RecoveringDialogFragment? = null +// private var dialogRecovering: RecoveringDialogFragment? = null - private var dialogDeleting: DeletingDialogFragment? = null +// private var dialogDeleting: DeletingDialogFragment? = null private var dialogConfirmDelete: ConfirmDeleteDialogFragment? = null //详情页面进行删除操作的监听 @@ -29,45 +32,45 @@ object RecoverOrDeleteManager { * 显示恢复中弹窗 */ fun showRecoveringDialog( - fragmentManager: FragmentManager, - scope: CoroutineScope, + activity: FragmentActivity, selectedSetList: Set, onComplete: (number: Int) -> Unit ) { - - dialogRecovering = dialogRecovering ?: RecoveringDialogFragment() - dialogRecovering?.run { - total = selectedSetList.size - completeListener = { number -> - onComplete(number) - dialogRecovering?.dismiss() - } - show(fragmentManager, "") - } - scope.copySelectedFilesAsync( + val dialog = RecoveringDialogFragment.show( + activity.supportFragmentManager, + selectedSetList.size + ) + activity.copySelectedFilesAsync( selectedSet = selectedSetList, folder = Common.recoveryPhotoDir, onProgress = { currentCounts: Int, data: ResultDataFiles, fileName: String, success: Boolean -> - if(success){ - ScanManager.showLog("--------恢复图片 ", "----------${currentCounts} ${fileName}") - dialogRecovering?.updateProgress(currentCounts) + if (success && !activity.isFinishing) { + ScanManager.showLog( + "--------恢复图片 ", + "----------${currentCounts} ${fileName}" + ) + dialog.updateProgress(currentCounts) ObjectBoxManager.addRecoveryFile(data) } }) { counts -> - dialogRecovering?.updateProgress(counts) - ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") + if (!activity.isFinishing) { + dialog.updateProgress(counts) + onComplete(counts) + dialog.dismissAllowingStateLoss() + ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") + } + } } /** - * 显示删除中弹窗 + * 显示确认删除弹窗 */ fun showConfirmDeleteDialog( isInfoDelete: Boolean = false, - fragmentManager: FragmentManager, - scope: CoroutineScope, + activity: FragmentActivity, selectedSetList: Set, onComplete: (number: Int) -> Unit ) { @@ -76,48 +79,48 @@ object RecoverOrDeleteManager { onClickDelete = { showDeletingDialog( isInfoDelete, - fragmentManager, - scope, + activity, selectedSetList, onComplete ) } - show(fragmentManager, "") + + safeShow(activity.supportFragmentManager, Common.TAG_DIALOG_CONFIRM_DELETE) + + } } + /** + * 显示删除中弹窗 + */ private fun showDeletingDialog( isInfoDelete: Boolean = false, - fragmentManager: FragmentManager, - scope: CoroutineScope, + activity: FragmentActivity, selectedSetList: Set, onComplete: (number: Int) -> Unit ) { - - 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, "") - } - scope.deleteFilesAsync( + val dialog = DeletingDialogFragment.show( + activity.supportFragmentManager, + selectedSetList.size + ) + activity.deleteFilesAsync( selectedSet = selectedSetList, onProgress = { currentCounts: Int, data: ResultDataFiles, path: String, success: Boolean -> - if (success){ + if (success) { ScanManager.showLog("--------删除图片 ", "----------${currentCounts} ${path}") - dialogDeleting?.updateProgress(currentCounts) + dialog.updateProgress(currentCounts) } }) { counts -> - dialogDeleting?.updateProgress(counts) - ScanManager.showLog("--------恢复图片 ", "----------恢复完成 ${counts}") + if (isInfoDelete && selectedSetList.size == 1) { + onSingleDeletedCompleteListener?.invoke(selectedSetList.first()) + } + onComplete(counts) + dialog.updateProgress(counts) + dialog.dismissAllowingStateLoss() + ScanManager.showLog("--------删除图片 ", "----------删除完成 ${counts}") } } } \ No newline at end of file diff --git a/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoveringDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoveringDialogFragment.kt index 1b8a1ba..a1be364 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoveringDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/sort/RecoveringDialogFragment.kt @@ -1,14 +1,33 @@ package com.ux.video.file.filerecovery.sort +import androidx.fragment.app.FragmentManager import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.base.BaseIngDialogFragment import com.ux.video.file.filerecovery.databinding.DialogRecoveringBinding +import com.ux.video.file.filerecovery.utils.Common +import com.ux.video.file.filerecovery.utils.ExtendFunctions.safeShow /** * 恢复中弹窗 */ class RecoveringDialogFragment() : BaseIngDialogFragment() { + + + companion object { + val TAG = Common.TAG_DIALOG_RECOVERING + + fun show( + fm: FragmentManager, + total: Int + ): RecoveringDialogFragment { + val dialog = RecoveringDialogFragment() + dialog.total = total + dialog.safeShow(fm, TAG) + return dialog + } + } + 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/sort/SortDialogFragment.kt b/app/src/main/java/com/ux/video/file/filerecovery/sort/SortDialogFragment.kt index 907e712..d84a659 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/sort/SortDialogFragment.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/sort/SortDialogFragment.kt @@ -11,14 +11,18 @@ import androidx.fragment.app.DialogFragment import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.databinding.CommonLayoutSortItemBinding import com.ux.video.file.filerecovery.databinding.DialogSortBinding +import com.ux.video.file.filerecovery.recovery.ui.recoveryphoto.RecoveredFragment -class SortDialogFragment(val onClickSort: (type: Int) -> Unit) : DialogFragment() { +class SortDialogFragment() : DialogFragment() { private lateinit var binding: DialogSortBinding private var clickType = SortingActivity.SORT_DESC_DATE private lateinit var LayoutList: List + + lateinit var onClickSort: (type: Int) -> Unit + override fun onStart() { super.onStart() dialog?.window?.apply { diff --git a/app/src/main/java/com/ux/video/file/filerecovery/sort/SortingActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/sort/SortingActivity.kt index 8e580a7..f6af47d 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/sort/SortingActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/sort/SortingActivity.kt @@ -34,6 +34,7 @@ import com.ux.video.file.filerecovery.utils.ExtendFunctions.kbToBytes import com.ux.video.file.filerecovery.utils.ExtendFunctions.mbToBytes import com.ux.video.file.filerecovery.utils.ExtendFunctions.minutesToMillisecond import com.ux.video.file.filerecovery.utils.ExtendFunctions.removeItem +import com.ux.video.file.filerecovery.utils.ExtendFunctions.safeShow import com.ux.video.file.filerecovery.utils.FileType import com.ux.video.file.filerecovery.utils.GridSpacingItemDecoration import com.ux.video.file.filerecovery.utils.ScanType @@ -250,8 +251,7 @@ class SortingActivity : BaseActivity() { } tvRecover.setOnClickListener { RecoverOrDeleteManager.showRecoveringDialog( - supportFragmentManager, - lifecycleScope, + this@SortingActivity, filterSelectedSetList ) { count -> complete(count, 0) @@ -260,8 +260,7 @@ class SortingActivity : BaseActivity() { } tvDelete.setOnClickListener { RecoverOrDeleteManager.showConfirmDeleteDialog( - fragmentManager = supportFragmentManager, - scope = lifecycleScope, + activity = this@SortingActivity, selectedSetList = filterSelectedSetList ) { count -> complete(count, 1) @@ -269,7 +268,8 @@ class SortingActivity : BaseActivity() { } imSort.setOnClickListener { - sortDialogFragment = sortDialogFragment ?: SortDialogFragment { + sortDialogFragment = sortDialogFragment ?: SortDialogFragment() + sortDialogFragment?.onClickSort = { when (it) { SORT_ASC_DATE -> { setDateAdapter() @@ -334,7 +334,7 @@ class SortingActivity : BaseActivity() { } } } - sortDialogFragment?.show(supportFragmentManager, "") + sortDialogFragment?.safeShow(supportFragmentManager, Common.TAG_DIALOG_SORT) } //全选按钮 只对当前显示的数据有效 @@ -806,7 +806,7 @@ class SortingActivity : BaseActivity() { onClickCancel = { } - show(supportFragmentManager, "") + safeShow(supportFragmentManager, Common.TAG_DIALOG_DATE_START) } @@ -842,9 +842,9 @@ class SortingActivity : BaseActivity() { } onClickCancel = { -// filterDatePopupWindows?.dismiss() + } - show(supportFragmentManager, "") + safeShow(supportFragmentManager, Common.TAG_DIALOG_DATE_END) } } 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 97c5ab7..550bc1f 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,6 +3,7 @@ package com.ux.video.file.filerecovery.success import android.content.Intent import android.view.LayoutInflater import androidx.core.view.isVisible +import com.bumptech.glide.Glide import com.ux.video.file.filerecovery.R import com.ux.video.file.filerecovery.base.BaseActivity import com.ux.video.file.filerecovery.databinding.ActivityRecoverOrDeletedSuccessBinding @@ -55,7 +56,10 @@ class RecoverySuccessActivity : BaseActivity { - imageCenter.setImageResource(R.drawable.image_recover_success) +// imageCenter.setImageResource(R.drawable.image_recover_success) + Glide.with(this@RecoverySuccessActivity) + .load(R.drawable.image_recover_success) + .into(imageCenter) tvNumber.setTextColor( Common.getColorInt( this@RecoverySuccessActivity, @@ -80,7 +84,10 @@ class RecoverySuccessActivity : BaseActivity { - imageCenter.setImageResource(R.drawable.image_deleted_success) +// imageCenter.setImageResource(R.drawable.image_deleted_success) + Glide.with(this@RecoverySuccessActivity) + .load(R.drawable.image_deleted_success) + .into(imageCenter) tvNumber.setTextColor( Common.getColorInt( this@RecoverySuccessActivity, 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 5b79b4a..c613e2b 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 @@ -32,6 +32,29 @@ object Common { val KEY_FILE_TYPE = "key_file_type" + //恢复中弹窗tag + val TAG_DIALOG_RECOVERING = "Dialog_Recovering" + + //删除中弹窗tag + val TAG_DIALOG_DELETEING = "Dialog_Deleting" + + //确认删除弹窗tag + val TAG_DIALOG_CONFIRM_DELETE = "Dialog_Confirm_Delete" + + //请求管理所有文件弹窗tag + val TAG_DIALOG_PERMISSION = "Dialog_Permission" + + //推出扫描结果弹窗tag + val TAG_DIALOG_EXIT = "Dialog_Exit" + + //排序弹窗tag + val TAG_DIALOG_SORT = "Dialog_Sort" + + //筛选开始日期弹窗tag + val TAG_DIALOG_DATE_START = "Dialog_start_date" + + //筛选结束日期弹窗tag + val TAG_DIALOG_DATE_END = "Dialog_end_date" val rootDir = Environment.getExternalStorageDirectory() 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 03fee9b..6bb2dc7 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 @@ -6,6 +6,8 @@ import android.icu.util.Calendar import android.os.Build import android.os.Parcelable import android.util.TypedValue +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView import com.ux.video.file.filerecovery.db.ResultDataFiles import com.ux.video.file.filerecovery.db.duration @@ -80,9 +82,6 @@ object ExtendFunctions { } - - - fun List>>.filterWithinDateRange( months: Int = -1, startDate: Date? = null, @@ -119,6 +118,7 @@ object ExtendFunctions { } } } + /** * 按文件大小筛选:区间 [minSize, maxSize] */ @@ -217,4 +217,21 @@ object ExtendFunctions { } + + fun DialogFragment.safeShow(fragmentManager: FragmentManager, tag: String) { + if (tag.isBlank()) throw IllegalArgumentException("Fragment tag cannot be blank") + + val existingFragment = fragmentManager.findFragmentByTag(tag) + if (existingFragment != null) { + return + } + if (!this.isAdded && !this.isVisible) { + try { + this.show(fragmentManager, tag) + } catch (e: IllegalStateException) { + e.printStackTrace() + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanManager.kt b/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanManager.kt index 8e210e4..fb8c70a 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanManager.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/utils/ScanManager.kt @@ -10,6 +10,9 @@ import android.provider.MediaStore import android.provider.OpenableColumns import android.text.format.Formatter import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope import com.ux.video.file.filerecovery.db.ResultData import com.ux.video.file.filerecovery.db.ResultDataFiles import kotlinx.coroutines.CoroutineScope @@ -65,7 +68,7 @@ object ScanManager { if (file.isDirectory) { scanDocuments(file, depth + 1) } else { - val fileCheckBoolean: Boolean = checkFileFormat(file,fileType) + val fileCheckBoolean: Boolean = checkFileFormat(file, fileType) if (fileCheckBoolean) { val dirName = file.parentFile?.name ?: "Unknown" @@ -135,7 +138,7 @@ object ScanManager { fun scanHiddenPhotoAsync( context: Context, root: File, maxDepth: Int = 5, - maxFiles: Int = 5000, fileType: FileType + maxFiles: Int = 5000, fileType: FileType ): Flow = flow { // scanRecycler(context) val result = mutableMapOf>() @@ -161,7 +164,7 @@ object ScanManager { val isHidden = file.name.startsWith(".") scanDir(file, depth + 1, insideHidden = insideHidden || isHidden) } else { - val fileCheckBoolean: Boolean = checkFileFormat(file,fileType) + val fileCheckBoolean: Boolean = checkFileFormat(file, fileType) if (insideHidden) { if (fileCheckBoolean) { val dirName = file.parentFile?.name ?: "Unknown" @@ -269,7 +272,6 @@ object ScanManager { } - private fun getFileSizeByMediaStore(context: Context, file: File): Long { val uri = Uri.fromFile(file) context.contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null) @@ -329,19 +331,25 @@ object ScanManager { * 做批量恢复 * @param folder "AllRecovery/Photo" */ - fun CoroutineScope.copySelectedFilesAsync( + fun LifecycleOwner.copySelectedFilesAsync( selectedSet: Set, rootDir: File = Common.rootDir, folder: String, onProgress: (currentCounts: Int, data: ResultDataFiles, fileName: String, success: Boolean) -> Unit, onComplete: (currentCounts: Int) -> Unit ) { - launch(Dispatchers.IO) { + lifecycleScope.launch(Dispatchers.IO) { var recoveryCount = 0 val targetDir = File(rootDir, folder) if (!targetDir.exists()) targetDir.mkdirs() selectedSet.forEachIndexed { index, resultPhotosFiles -> - val srcFile = File(resultPhotosFiles.path!!) + // 页面已销毁,直接停 + if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { + Common.showLog("----------------页面已销毁,直接停") + return@launch + } + Common.showLog("----------------resultPhotosFiles.path=${resultPhotosFiles.path}") + val srcFile = File(resultPhotosFiles.path) if (srcFile.exists() && srcFile.isFile) { val destFile = File(targetDir, srcFile.name) var success = false @@ -351,12 +359,17 @@ object ScanManager { input.copyTo(output) } } + + success = destFile.exists() && destFile.length() > 0 + Common.showLog("------------success------${success}") success = true recoveryCount++ withContext(Dispatchers.Main) { - onProgress(index + 1, resultPhotosFiles, srcFile.name, success) + if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) + onProgress(index + 1, resultPhotosFiles, srcFile.name, success) } } catch (e: Exception) { + Common.showLog("------------Exception------${e.message}") e.printStackTrace() } @@ -364,7 +377,8 @@ object ScanManager { } withContext(Dispatchers.Main) { - onComplete(recoveryCount) + if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) + onComplete(recoveryCount) } } } @@ -374,12 +388,12 @@ object ScanManager { * 做批量删除文件 * */ - fun CoroutineScope.deleteFilesAsync( + fun LifecycleOwner.deleteFilesAsync( selectedSet: Set, onProgress: (currentCounts: Int, data: ResultDataFiles, fileName: String, success: Boolean) -> Unit, onComplete: (currentCounts: Int) -> Unit ) { - launch(Dispatchers.IO) { + lifecycleScope.launch(Dispatchers.IO) { var deletedCount = 0 selectedSet.forEachIndexed { index, resultPhotosFiles -> try { diff --git a/app/src/main/java/com/ux/video/file/filerecovery/video/VideoPlayActivity.kt b/app/src/main/java/com/ux/video/file/filerecovery/video/VideoPlayActivity.kt index fd869ad..01c33eb 100644 --- a/app/src/main/java/com/ux/video/file/filerecovery/video/VideoPlayActivity.kt +++ b/app/src/main/java/com/ux/video/file/filerecovery/video/VideoPlayActivity.kt @@ -69,8 +69,7 @@ class VideoPlayActivity : BaseActivity() { setOnClickListener { RecoverOrDeleteManager.showConfirmDeleteDialog( true, - supportFragmentManager, - lifecycleScope, + this@VideoPlayActivity, setOf(resultPhotosFiles) ) { count -> complete(count, 1) @@ -82,8 +81,7 @@ class VideoPlayActivity : BaseActivity() { text = resources.getString(R.string.recover) setOnClickListener { RecoverOrDeleteManager.showRecoveringDialog( - supportFragmentManager, - lifecycleScope, + this@VideoPlayActivity, setOf(resultPhotosFiles) ) { count -> complete(count, 0) diff --git a/app/src/main/res/drawable/image_deleted_success.png b/app/src/main/res/drawable/image_deleted_success.png index bd897d4..10ccc6f 100644 Binary files a/app/src/main/res/drawable/image_deleted_success.png and b/app/src/main/res/drawable/image_deleted_success.png differ diff --git a/app/src/main/res/drawable/image_recover_success.png b/app/src/main/res/drawable/image_recover_success.png index ff06fae..383f5c7 100644 Binary files a/app/src/main/res/drawable/image_recover_success.png and b/app/src/main/res/drawable/image_recover_success.png differ