视频播放
@ -55,4 +55,6 @@ dependencies {
|
||||
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||
implementation ("com.google.android.material:material:1.13.0")
|
||||
implementation(project(":pickerview"))
|
||||
implementation ("androidx.media3:media3-exoplayer:1.8.0")
|
||||
implementation ("androidx.media3:media3-ui:1.8.0")
|
||||
}
|
||||
@ -24,6 +24,9 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.FileRecovery"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".video.VideoPlayActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".photo.PhotoInfoActivity"
|
||||
android:exported="false" />
|
||||
|
||||
@ -20,13 +20,15 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
setContentView(binding.root)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
if(addPadding()){
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
}
|
||||
insets
|
||||
}
|
||||
initView()
|
||||
initData()
|
||||
}
|
||||
|
||||
protected open fun addPadding() = true
|
||||
protected abstract fun inflateBinding(inflater: LayoutInflater): VB
|
||||
|
||||
protected open fun initView() {}
|
||||
|
||||
@ -17,6 +17,10 @@ import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_video
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
/**
|
||||
* 选择扫描所有文件还是扫描删除过的文件
|
||||
*/
|
||||
class ScanSelectTypeActivity : BaseActivity<ActivityScanSelectTypeBinding>() {
|
||||
|
||||
companion object {
|
||||
|
||||
@ -23,6 +23,9 @@ import org.jaaksi.pickerview.picker.TimePicker.OnTimeSelectListener
|
||||
import org.jaaksi.pickerview.widget.DefaultCenterDecoration
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
* 自定义日期筛选,选择日期弹窗
|
||||
*/
|
||||
class DatePickerDialogFragment(
|
||||
var mContext: Context,
|
||||
var title: String,
|
||||
|
||||
@ -7,6 +7,7 @@ import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.ux.video.file.filerecovery.base.BaseAdapter
|
||||
import com.ux.video.file.filerecovery.base.DiffBaseAdapter
|
||||
import com.ux.video.file.filerecovery.databinding.PhotoDisplayDateAdapterBinding
|
||||
@ -16,6 +17,7 @@ import com.ux.video.file.filerecovery.utils.ScanRepository
|
||||
|
||||
class PhotoDisplayDateAdapter(
|
||||
mContext: Context,
|
||||
var scanType: Int,
|
||||
var mColumns: Int,
|
||||
var viewModel: ScanRepository,
|
||||
var onSelectedUpdate: (resultPhotosFiles: ResultPhotosFiles, isAdd: Boolean) -> Unit,
|
||||
@ -34,14 +36,13 @@ class PhotoDisplayDateAdapter(
|
||||
)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 返回所有嵌套的数据量总数
|
||||
*/
|
||||
fun getTotalChildCount(hideThumbnails: Boolean): Int {
|
||||
if(hideThumbnails){
|
||||
if (hideThumbnails) {
|
||||
return data.sumOf { it.second.filter { !it.isThumbnail }.size }
|
||||
}else{
|
||||
} else {
|
||||
return data.sumOf { it.second.size }
|
||||
}
|
||||
|
||||
@ -81,17 +82,18 @@ class PhotoDisplayDateAdapter(
|
||||
val (date, files) = item
|
||||
val childAdapter = PhotoDisplayDateChildAdapter(
|
||||
mContext,
|
||||
scanType,
|
||||
mColumns,
|
||||
viewModel,
|
||||
{ resultPhotosFiles, addOrRemove, isDateAllSelected ->
|
||||
//点击当前Adapter某一天的全选或者子Item上的选中都会回调到这里
|
||||
tvDayAllSelect.isSelected = isDateAllSelected
|
||||
onSelectedUpdate(resultPhotosFiles, addOrRemove)
|
||||
}, { updateHideThumbnails->
|
||||
}, { updateHideThumbnails ->
|
||||
|
||||
tvDayAllSelect.isSelected = updateHideThumbnails
|
||||
|
||||
},clickItem
|
||||
}, clickItem
|
||||
).apply { setData(files) }
|
||||
|
||||
allSelected?.let {
|
||||
@ -106,7 +108,15 @@ class PhotoDisplayDateAdapter(
|
||||
textChildCounts.text = "(${files.size})"
|
||||
|
||||
recyclerChild.apply {
|
||||
layoutManager = GridLayoutManager(context, mColumns)
|
||||
layoutManager = when (scanType) {
|
||||
Common.VALUE_SCAN_TYPE_audio, Common.VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
LinearLayoutManager(context)
|
||||
}
|
||||
else -> {
|
||||
GridLayoutManager(context, mColumns)
|
||||
}
|
||||
}
|
||||
|
||||
adapter = childAdapter
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
|
||||
@ -18,9 +18,11 @@ import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.ux.video.file.filerecovery.App
|
||||
import com.ux.video.file.filerecovery.R
|
||||
import com.ux.video.file.filerecovery.base.NewBaseAdapter
|
||||
import com.ux.video.file.filerecovery.databinding.FileSpanCountThreeAdapterBinding
|
||||
import com.ux.video.file.filerecovery.databinding.FileSpanCountTwoAdapterBinding
|
||||
import com.ux.video.file.filerecovery.databinding.OneAudioDocumentsItemBinding
|
||||
import com.ux.video.file.filerecovery.utils.Common
|
||||
import com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.dpToPx
|
||||
@ -29,6 +31,7 @@ import com.ux.video.file.filerecovery.utils.ScanRepository
|
||||
|
||||
class PhotoDisplayDateChildAdapter(
|
||||
mContext: Context,
|
||||
var scanType: Int,
|
||||
var mColumns: Int,
|
||||
var viewModel: ScanRepository,
|
||||
/**
|
||||
@ -38,8 +41,8 @@ class PhotoDisplayDateChildAdapter(
|
||||
* @param dateAllSelected 这组数据是否全部选中(某一天)
|
||||
*/
|
||||
var onSelectedUpdate: (resultPhotosFiles: ResultPhotosFiles, addOrRemove: Boolean, dateAllSelected: Boolean) -> Unit,
|
||||
var hideThumbnailsUpdate:(dateAllSelected: Boolean)-> Unit,
|
||||
var clickItem:(item:ResultPhotosFiles)-> Unit
|
||||
var hideThumbnailsUpdate: (dateAllSelected: Boolean) -> Unit,
|
||||
var clickItem: (item: ResultPhotosFiles) -> Unit
|
||||
) :
|
||||
NewBaseAdapter<ResultPhotosFiles>(mContext) {
|
||||
|
||||
@ -49,10 +52,13 @@ class PhotoDisplayDateChildAdapter(
|
||||
|
||||
|
||||
companion object {
|
||||
//音频或者文档
|
||||
private const val TYPE_ONE = 1
|
||||
private const val TYPE_TWO = 2
|
||||
private const val TYPE_THREE = 3
|
||||
private const val TYPE_FOUR = 4
|
||||
}
|
||||
|
||||
fun setAllSelected(isAdd: Boolean) {
|
||||
data.forEach {
|
||||
addOrRemove(it, isAdd)
|
||||
@ -61,12 +67,22 @@ class PhotoDisplayDateChildAdapter(
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when (mColumns) {
|
||||
2 -> TYPE_TWO
|
||||
3 -> TYPE_THREE
|
||||
4 -> TYPE_FOUR
|
||||
else -> TYPE_THREE
|
||||
when (scanType) {
|
||||
Common.VALUE_SCAN_TYPE_audio, Common.VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
return TYPE_ONE
|
||||
}
|
||||
|
||||
else -> {
|
||||
return when (mColumns) {
|
||||
2 -> TYPE_TWO
|
||||
3 -> TYPE_THREE
|
||||
4 -> TYPE_FOUR
|
||||
else -> TYPE_THREE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun setColumns(int: Int) {
|
||||
@ -82,7 +98,7 @@ class PhotoDisplayDateChildAdapter(
|
||||
val screenWidth = view.context.resources.displayMetrics.widthPixels
|
||||
val i = (Common.itemSpacing).dpToPx(App.mAppContext) * (mColumns - 1)
|
||||
val itemSize =
|
||||
(screenWidth - i - 2 * Common.horizontalSpacing.dpToPx(App.mAppContext) )/ mColumns
|
||||
(screenWidth - i - 2 * Common.horizontalSpacing.dpToPx(App.mAppContext)) / mColumns
|
||||
view.layoutParams = layoutParams.apply {
|
||||
height = itemSize
|
||||
}
|
||||
@ -94,6 +110,14 @@ class PhotoDisplayDateChildAdapter(
|
||||
): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return when (viewType) {
|
||||
TYPE_ONE -> OneHolder(
|
||||
OneAudioDocumentsItemBinding.inflate(
|
||||
inflater,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
TYPE_TWO -> TwoHolder(
|
||||
FileSpanCountTwoAdapterBinding.inflate(
|
||||
inflater,
|
||||
@ -121,13 +145,34 @@ class PhotoDisplayDateChildAdapter(
|
||||
|
||||
when (holder) {
|
||||
is TwoHolder -> holder.vb.run {
|
||||
|
||||
initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item)
|
||||
initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item, imageType)
|
||||
}
|
||||
|
||||
is ThreeHolder -> holder.vb.run {
|
||||
initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item, imageType)
|
||||
}
|
||||
|
||||
initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item)
|
||||
is OneHolder -> {
|
||||
item.run {
|
||||
holder.vb.let {
|
||||
it.textName.text = name
|
||||
it.textDuration.text = Common.formatDuration(duration)
|
||||
it.textSize.text = sizeString
|
||||
|
||||
|
||||
viewModel.checkIsSelect(this).let { isSelected ->
|
||||
it.imageSelect.isSelected = isSelected
|
||||
addOrRemove(this, isSelected)
|
||||
}
|
||||
it.imageSelect.setOnClickListener {
|
||||
it.isSelected = !it.isSelected
|
||||
it.isSelected.let { newStatus ->
|
||||
addOrRemove(this, newStatus)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,15 +184,19 @@ class PhotoDisplayDateChildAdapter(
|
||||
class TwoHolder(val vb: FileSpanCountTwoAdapterBinding) :
|
||||
RecyclerView.ViewHolder(vb.root)
|
||||
|
||||
class OneHolder(val vb: OneAudioDocumentsItemBinding) :
|
||||
RecyclerView.ViewHolder(vb.root)
|
||||
|
||||
private fun initDateView(
|
||||
rootLayout: RelativeLayout,
|
||||
imageSelectStatus: ImageView,
|
||||
textSize: CustomTextView,
|
||||
imageThumbnail: ImageView,
|
||||
item: ResultPhotosFiles
|
||||
item: ResultPhotosFiles,
|
||||
imageType: ImageView
|
||||
) {
|
||||
item.run {
|
||||
|
||||
viewModel.checkIsSelect(this).let {
|
||||
imageSelectStatus.isSelected = it
|
||||
addOrRemove(this, it)
|
||||
@ -160,6 +209,13 @@ class PhotoDisplayDateChildAdapter(
|
||||
}
|
||||
textSize.text = sizeString
|
||||
|
||||
imageType.setImageResource(
|
||||
when (scanType) {
|
||||
Common.VALUE_SCAN_TYPE_photo, Common.VALUE_SCAN_TYPE_deleted_photo -> R.drawable.icon_type_photo
|
||||
Common.VALUE_SCAN_TYPE_video, Common.VALUE_SCAN_TYPE_deleted_video -> R.drawable.icon_type_video
|
||||
else -> R.drawable.icon_type_photo
|
||||
}
|
||||
)
|
||||
Glide.with(mContext)
|
||||
.load(targetFile)
|
||||
.apply(
|
||||
@ -211,14 +267,4 @@ class PhotoDisplayDateChildAdapter(
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getVisibleCount(list: MutableList<ResultPhotosFiles> = data, hideThumbnails: Boolean): Int {
|
||||
if(hideThumbnails){
|
||||
return list.filter { !it.isThumbnail }.size
|
||||
}else{
|
||||
return list.size
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,12 +3,8 @@ package com.ux.video.file.filerecovery.photo
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.DataSource
|
||||
@ -21,12 +17,19 @@ import com.bumptech.glide.request.target.Target
|
||||
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.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
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_documents
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_video
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_documents
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_video
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.dpToPx
|
||||
import com.ux.video.file.filerecovery.utils.ScanManager
|
||||
import com.ux.video.file.filerecovery.video.VideoPlayActivity
|
||||
|
||||
class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
|
||||
|
||||
@ -34,6 +37,7 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
|
||||
val KEY_CLICK_ITEM = "click_item"
|
||||
}
|
||||
|
||||
private var scanType: Int = VALUE_SCAN_TYPE_photo
|
||||
private var myData: ResultPhotosFiles? = null
|
||||
|
||||
override fun inflateBinding(inflater: LayoutInflater): ActivityPhotoInfoBinding =
|
||||
@ -45,31 +49,34 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
|
||||
intent.getParcelableExtra(KEY_CLICK_ITEM, ResultPhotosFiles::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
intent.getParcelableExtra("MY_KEY")
|
||||
intent.getParcelableExtra(KEY_CLICK_ITEM)
|
||||
}
|
||||
scanType = intent.getIntExtra(KEY_SCAN_TYPE, VALUE_SCAN_TYPE_photo)
|
||||
setView()
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
binding.run {
|
||||
imageViewBack.setOnClickListener { finish() }
|
||||
myData?.let { resultPhotosFiles->
|
||||
myData?.let { resultPhotosFiles ->
|
||||
|
||||
tvName.text = resultPhotosFiles.name
|
||||
tvPath.text = resultPhotosFiles.path
|
||||
tvDate.text = Common.getFormatDate(resultPhotosFiles.lastModified)
|
||||
tvResolution.text = resultPhotosFiles.resolution
|
||||
tvDuration.text = Common.formatDuration(resultPhotosFiles.duration)
|
||||
|
||||
Glide.with(this@PhotoInfoActivity)
|
||||
.load(resultPhotosFiles.targetFile)
|
||||
.apply(
|
||||
RequestOptions()
|
||||
.transform(
|
||||
CenterCrop(),
|
||||
RoundedCorners(8.dpToPx(this@PhotoInfoActivity))
|
||||
)
|
||||
)
|
||||
.apply(RequestOptions().transform(CenterCrop(), RoundedCorners(8.dpToPx(this@PhotoInfoActivity))))
|
||||
.listener(object : RequestListener<Drawable> {
|
||||
override fun onLoadFailed(
|
||||
e: GlideException?,
|
||||
model: Any?,
|
||||
target: com.bumptech.glide.request.target.Target<Drawable?>,
|
||||
target: Target<Drawable?>,
|
||||
isFirstResource: Boolean
|
||||
): Boolean {
|
||||
return false
|
||||
@ -92,8 +99,13 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
|
||||
layoutBottom.tvLeft.run {
|
||||
text = resources.getString(R.string.delete)
|
||||
setOnClickListener {
|
||||
RecoverOrDeleteManager.showConfirmDeleteDialog(true,supportFragmentManager,lifecycleScope,setOf(resultPhotosFiles)){count->
|
||||
complete(count,1)
|
||||
RecoverOrDeleteManager.showConfirmDeleteDialog(
|
||||
true,
|
||||
supportFragmentManager,
|
||||
lifecycleScope,
|
||||
setOf(resultPhotosFiles)
|
||||
) { count ->
|
||||
complete(count, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -101,8 +113,12 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
|
||||
layoutBottom.tvRight.run {
|
||||
text = resources.getString(R.string.recover)
|
||||
setOnClickListener {
|
||||
RecoverOrDeleteManager.showRecoveringDialog(supportFragmentManager,lifecycleScope,setOf(resultPhotosFiles)){count->
|
||||
complete(count,0)
|
||||
RecoverOrDeleteManager.showRecoveringDialog(
|
||||
supportFragmentManager,
|
||||
lifecycleScope,
|
||||
setOf(resultPhotosFiles)
|
||||
) { count ->
|
||||
complete(count, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,11 +126,74 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun complete(number: Int,type: Int) {
|
||||
private fun setView() {
|
||||
binding.run {
|
||||
when (scanType) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo -> {
|
||||
layoutName.isVisible = true
|
||||
layoutPath.isVisible = true
|
||||
layoutResolution.isVisible = true
|
||||
layoutDate.isVisible = true
|
||||
|
||||
layoutType.isVisible = false
|
||||
layoutSize.isVisible = false
|
||||
layoutDuration.isVisible = false
|
||||
|
||||
imPlay.isVisible = false
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video -> {
|
||||
layoutName.isVisible = true
|
||||
layoutPath.isVisible = true
|
||||
layoutResolution.isVisible = true
|
||||
layoutDate.isVisible = true
|
||||
layoutDuration.isVisible = true
|
||||
|
||||
layoutType.isVisible = false
|
||||
layoutSize.isVisible = false
|
||||
|
||||
imPlay.isVisible = true
|
||||
myData?.let { data->
|
||||
frameImage.setOnClickListener {
|
||||
startActivity(Intent(this@PhotoInfoActivity, VideoPlayActivity::class.java).apply {
|
||||
putExtra(VideoPlayActivity.KEY_DATA, data)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
layoutName.isVisible = true
|
||||
layoutPath.isVisible = true
|
||||
layoutSize.isVisible = true
|
||||
layoutDate.isVisible = true
|
||||
layoutDuration.isVisible = true
|
||||
|
||||
layoutResolution.isVisible = false
|
||||
layoutType.isVisible = false
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
layoutName.isVisible = true
|
||||
layoutType.isVisible = true
|
||||
layoutPath.isVisible = true
|
||||
layoutSize.isVisible = true
|
||||
layoutDate.isVisible = true
|
||||
|
||||
layoutDuration.isVisible = false
|
||||
layoutDuration.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
putExtra(RecoverySuccessActivity.KEY_SUCCESS_COUNT, number)
|
||||
putExtra(RecoverySuccessActivity.KEY_SUCCESS_TYPE, type)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
@ -13,8 +14,19 @@ import com.ux.video.file.filerecovery.base.BaseActivity
|
||||
import com.ux.video.file.filerecovery.databinding.ActivityPhotoSortingBinding
|
||||
import com.ux.video.file.filerecovery.success.RecoverySuccessActivity
|
||||
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
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_documents
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_deleted_video
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_documents
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_video
|
||||
import com.ux.video.file.filerecovery.utils.Common.setItemSelect
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.dpToPx
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterByDuration
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterByDurationList
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterBySize
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterBySizeList
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterRemoveThumbnailsAsync
|
||||
@ -22,12 +34,11 @@ import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterThumbnailsAsyn
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.filterWithinDateRange
|
||||
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.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.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
|
||||
@ -57,6 +68,8 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
val SORT_DESC_DATE = 3
|
||||
}
|
||||
|
||||
private var scanType: Int = VALUE_SCAN_TYPE_photo
|
||||
|
||||
private var sortDialogFragment: SortDialogFragment? = null
|
||||
private var columns = 3
|
||||
private var dateAdapter: PhotoDisplayDateAdapter? = null
|
||||
@ -76,7 +89,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
private var filterDate = FILTER_DATE_ALL
|
||||
|
||||
//筛选大小,默认全部-1
|
||||
private var filterSize = FILTER_SIZE_ALL
|
||||
private var filterSize: String = "All"
|
||||
|
||||
private var filterDatePopupWindows: DateFilterPopupWindows? = null
|
||||
private var filterStartDate: Date? = null
|
||||
@ -103,6 +116,8 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
|
||||
private lateinit var mItemDecoration: GridSpacingItemDecoration
|
||||
|
||||
private lateinit var sizeFilterItemArray: Array<String>
|
||||
|
||||
|
||||
private lateinit var viewModel: ScanRepository
|
||||
override fun inflateBinding(inflater: LayoutInflater): ActivityPhotoSortingBinding =
|
||||
@ -110,13 +125,12 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
|
||||
scanType = intent.getIntExtra(KEY_SCAN_TYPE, VALUE_SCAN_TYPE_photo)
|
||||
val list: ArrayList<ResultPhotosFiles>? =
|
||||
intent.getParcelableArrayListExtraCompat(KEY_PHOTO_FOLDER_FILE)
|
||||
mItemDecoration =
|
||||
GridSpacingItemDecoration(columns, Common.itemSpacing, Common.horizontalSpacing)
|
||||
updateButtonCounts(0)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(ScanRepository::class.java)
|
||||
|
||||
viewModel.selectedLiveData.observe(this) { selectedSet ->
|
||||
@ -129,12 +143,11 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
Common.showLog("当前显示筛选数据 选中状态更新: ${displaySet.size}")
|
||||
updateCurrentIsAllSelectStatus()
|
||||
}
|
||||
|
||||
setScanTypeView()
|
||||
list?.let {
|
||||
binding.tvThumbnailCounts.text =
|
||||
getString(R.string.hide_thumbnails, it.filter { it.isThumbnail }.size)
|
||||
|
||||
|
||||
//降序(最近的在前面)
|
||||
sortByDateReverse = Common.getSortByDayNewToOldInit(it)
|
||||
//升序(时间最远的在前面)
|
||||
@ -144,6 +157,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
|
||||
sizeSortAdapter = PhotoDisplayDateChildAdapter(
|
||||
this@PhotoSortingActivity,
|
||||
scanType,
|
||||
columns, viewModel,
|
||||
{ resultPhotosFiles, isAdd, allSelected ->
|
||||
viewModel.toggleSelection(isAdd, resultPhotosFiles)
|
||||
@ -156,6 +170,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
this@PhotoSortingActivity,
|
||||
PhotoInfoActivity::class.java
|
||||
).apply {
|
||||
putExtra(KEY_SCAN_TYPE,scanType)
|
||||
putExtra(PhotoInfoActivity.KEY_CLICK_ITEM, item)
|
||||
})
|
||||
|
||||
@ -163,6 +178,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
dateAdapter =
|
||||
PhotoDisplayDateAdapter(
|
||||
this@PhotoSortingActivity,
|
||||
scanType,
|
||||
columns,
|
||||
viewModel,
|
||||
{ actionPath, isAdd ->
|
||||
@ -173,6 +189,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
this@PhotoSortingActivity,
|
||||
PhotoInfoActivity::class.java
|
||||
).apply {
|
||||
putExtra(KEY_SCAN_TYPE,scanType)
|
||||
putExtra(PhotoInfoActivity.KEY_CLICK_ITEM, item)
|
||||
})
|
||||
}.apply {
|
||||
@ -182,166 +199,209 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
setDateAdapter()
|
||||
setSingleDelete()
|
||||
setFilter()
|
||||
binding.run {
|
||||
imageViewBack.setOnClickListener { finish() }
|
||||
switchHideThumbnails.setOnCheckedChangeListener { _, isChecked ->
|
||||
when (recyclerView.adapter) {
|
||||
is PhotoDisplayDateAdapter -> {
|
||||
lifecycleScope.launch {
|
||||
dateAdapter?.run {
|
||||
initGetCurrentDateList().let { list ->
|
||||
val filterThumbnailsAsync =
|
||||
if (isChecked) list.filterThumbnailsAsync() else list
|
||||
setData(filterThumbnailsAsync)
|
||||
checkRefreshDisPlaySelected(list1 = filterThumbnailsAsync)
|
||||
}
|
||||
setAllClick()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
is PhotoDisplayDateChildAdapter -> {
|
||||
lifecycleScope.launch {
|
||||
sizeSortAdapter?.run {
|
||||
initGetCurrentSizeList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (isChecked) it.filterRemoveThumbnailsAsync() else it
|
||||
setData(filterThumbnailsAsync)
|
||||
checkRefreshDisPlaySelected(list2 = filterThumbnailsAsync)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
updateCurrentIsAllSelectStatus()
|
||||
|
||||
}
|
||||
tvRecover.setOnClickListener {
|
||||
// showRecoveringDialog()
|
||||
RecoverOrDeleteManager.showRecoveringDialog(
|
||||
supportFragmentManager,
|
||||
lifecycleScope,
|
||||
filterSelectedSetList
|
||||
) { count ->
|
||||
complete(count, 0)
|
||||
}
|
||||
|
||||
}
|
||||
tvDelete.setOnClickListener {
|
||||
// showConfirmDeleteDialog()
|
||||
RecoverOrDeleteManager.showConfirmDeleteDialog(
|
||||
fragmentManager = supportFragmentManager,
|
||||
scope = lifecycleScope,
|
||||
selectedSetList = filterSelectedSetList
|
||||
) { count ->
|
||||
complete(count, 1)
|
||||
}
|
||||
|
||||
}
|
||||
imSort.setOnClickListener {
|
||||
sortDialogFragment = sortDialogFragment ?: SortDialogFragment {
|
||||
when (it) {
|
||||
SORT_ASC_DATE -> {
|
||||
setDateAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentDateList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterThumbnailsAsync() else it
|
||||
val sortByDayOldToNew =
|
||||
Common.getSortByDayOldToNew(filterThumbnailsAsync)
|
||||
dateAdapter?.setData(sortByDayOldToNew)
|
||||
resetCurrentDateList(sortByDayOldToNew)
|
||||
}
|
||||
sortReverse = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SORT_DESC_DATE -> {
|
||||
setDateAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentDateList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterThumbnailsAsync() else it
|
||||
val sortByDayNewToOld =
|
||||
Common.getSortByDayNewToOld(filterThumbnailsAsync)
|
||||
dateAdapter?.setData(sortByDayNewToOld)
|
||||
resetCurrentDateList(sortByDayNewToOld)
|
||||
}
|
||||
sortReverse = true
|
||||
}
|
||||
}
|
||||
|
||||
SORT_DESC_SIZE -> {
|
||||
setSizeAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentSizeList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterRemoveThumbnailsAsync() else it
|
||||
val sortBySizeBigToSmall =
|
||||
Common.getSortBySizeBigToSmall(filterThumbnailsAsync)
|
||||
sizeSortAdapter?.setData(sortBySizeBigToSmall)
|
||||
resetCurrentSizeList(sortBySizeBigToSmall)
|
||||
}
|
||||
sortReverse = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SORT_ASC_SIZE -> {
|
||||
setSizeAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentSizeList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterRemoveThumbnailsAsync() else it
|
||||
val sortBySizeSmallToBig =
|
||||
Common.getSortBySizeSmallToBig(filterThumbnailsAsync)
|
||||
sizeSortAdapter?.setData(sortBySizeSmallToBig)
|
||||
resetCurrentSizeList(sortBySizeSmallToBig)
|
||||
}
|
||||
sortReverse = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sortDialogFragment?.show(supportFragmentManager, "")
|
||||
}
|
||||
|
||||
//全选按钮 只对当前显示的数据有效
|
||||
tvSelectAll.setOnClickListener {
|
||||
it.isSelected = !it.isSelected
|
||||
when (binding.recyclerView.adapter) {
|
||||
is PhotoDisplayDateAdapter -> {
|
||||
dateAdapter?.setAllSelected(it.isSelected)
|
||||
dateAdapter?.getCurrentData()?.let {
|
||||
it as List<Pair<String, List<ResultPhotosFiles>>>
|
||||
|
||||
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<ResultPhotosFiles>
|
||||
if (it.size > 0)
|
||||
Common.showLog("------------全选按钮 大小-${it.size} ${it[0].path}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun setAllClick() {
|
||||
binding.run {
|
||||
imageViewBack.setOnClickListener { finish() }
|
||||
switchHideThumbnails.setOnCheckedChangeListener { _, isChecked ->
|
||||
when (recyclerView.adapter) {
|
||||
is PhotoDisplayDateAdapter -> {
|
||||
lifecycleScope.launch {
|
||||
dateAdapter?.run {
|
||||
initGetCurrentDateList().let { list ->
|
||||
val filterThumbnailsAsync =
|
||||
if (isChecked) list.filterThumbnailsAsync() else list
|
||||
setData(filterThumbnailsAsync)
|
||||
checkRefreshDisPlaySelected(list1 = filterThumbnailsAsync)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
is PhotoDisplayDateChildAdapter -> {
|
||||
lifecycleScope.launch {
|
||||
sizeSortAdapter?.run {
|
||||
initGetCurrentSizeList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (isChecked) it.filterRemoveThumbnailsAsync() else it
|
||||
setData(filterThumbnailsAsync)
|
||||
checkRefreshDisPlaySelected(list2 = filterThumbnailsAsync)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
updateCurrentIsAllSelectStatus()
|
||||
|
||||
}
|
||||
tvRecover.setOnClickListener {
|
||||
RecoverOrDeleteManager.showRecoveringDialog(
|
||||
supportFragmentManager,
|
||||
lifecycleScope,
|
||||
filterSelectedSetList
|
||||
) { count ->
|
||||
complete(count, 0)
|
||||
}
|
||||
|
||||
}
|
||||
tvDelete.setOnClickListener {
|
||||
RecoverOrDeleteManager.showConfirmDeleteDialog(
|
||||
fragmentManager = supportFragmentManager,
|
||||
scope = lifecycleScope,
|
||||
selectedSetList = filterSelectedSetList
|
||||
) { count ->
|
||||
complete(count, 1)
|
||||
}
|
||||
|
||||
}
|
||||
imSort.setOnClickListener {
|
||||
sortDialogFragment = sortDialogFragment ?: SortDialogFragment {
|
||||
when (it) {
|
||||
SORT_ASC_DATE -> {
|
||||
setDateAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentDateList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterThumbnailsAsync() else it
|
||||
val sortByDayOldToNew =
|
||||
Common.getSortByDayOldToNew(filterThumbnailsAsync)
|
||||
dateAdapter?.setData(sortByDayOldToNew)
|
||||
resetCurrentDateList(sortByDayOldToNew)
|
||||
}
|
||||
sortReverse = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SORT_DESC_DATE -> {
|
||||
setDateAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentDateList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterThumbnailsAsync() else it
|
||||
val sortByDayNewToOld =
|
||||
Common.getSortByDayNewToOld(filterThumbnailsAsync)
|
||||
dateAdapter?.setData(sortByDayNewToOld)
|
||||
resetCurrentDateList(sortByDayNewToOld)
|
||||
}
|
||||
sortReverse = true
|
||||
}
|
||||
}
|
||||
|
||||
SORT_DESC_SIZE -> {
|
||||
setSizeAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentSizeList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterRemoveThumbnailsAsync() else it
|
||||
val sortBySizeBigToSmall =
|
||||
Common.getSortBySizeBigToSmall(filterThumbnailsAsync)
|
||||
sizeSortAdapter?.setData(sortBySizeBigToSmall)
|
||||
resetCurrentSizeList(sortBySizeBigToSmall)
|
||||
}
|
||||
sortReverse = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SORT_ASC_SIZE -> {
|
||||
setSizeAdapter()
|
||||
lifecycleScope.launch {
|
||||
initGetCurrentSizeList().let {
|
||||
val filterThumbnailsAsync =
|
||||
if (switchHideThumbnails.isChecked) it.filterRemoveThumbnailsAsync() else it
|
||||
val sortBySizeSmallToBig =
|
||||
Common.getSortBySizeSmallToBig(filterThumbnailsAsync)
|
||||
sizeSortAdapter?.setData(sortBySizeSmallToBig)
|
||||
resetCurrentSizeList(sortBySizeSmallToBig)
|
||||
}
|
||||
sortReverse = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sortDialogFragment?.show(supportFragmentManager, "")
|
||||
}
|
||||
|
||||
//全选按钮 只对当前显示的数据有效
|
||||
tvSelectAll.setOnClickListener {
|
||||
it.isSelected = !it.isSelected
|
||||
when (binding.recyclerView.adapter) {
|
||||
is PhotoDisplayDateAdapter -> {
|
||||
dateAdapter?.setAllSelected(it.isSelected)
|
||||
dateAdapter?.getCurrentData()?.let {
|
||||
it as List<Pair<String, List<ResultPhotosFiles>>>
|
||||
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<ResultPhotosFiles>
|
||||
if (it.size > 0)
|
||||
Common.showLog("------------全选按钮 大小-${it.size} ${it[0].path}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 不同类型下的ui和功能点区分
|
||||
*/
|
||||
private fun setScanTypeView() {
|
||||
binding.run {
|
||||
when (scanType) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo -> {
|
||||
titleSize.text = getString(R.string.size)
|
||||
filterLayoutLinearlayout.isVisible = true
|
||||
relativeThumbnails.isVisible = true
|
||||
sizeFilterItemArray = resources.getStringArray(R.array.filter_size_photo)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video -> {
|
||||
titleSize.text = getString(R.string.duration)
|
||||
filterLayoutLinearlayout.isVisible = true
|
||||
relativeThumbnails.isVisible = false
|
||||
sizeFilterItemArray =
|
||||
resources.getStringArray(R.array.filter_duration_video_audio)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
titleSize.text = getString(R.string.duration)
|
||||
filterLayoutLinearlayout.isVisible = false
|
||||
relativeThumbnails.isVisible = false
|
||||
sizeFilterItemArray =
|
||||
resources.getStringArray(R.array.filter_duration_video_audio)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
titleSize.text = getString(R.string.size)
|
||||
filterLayoutLinearlayout.isVisible = false
|
||||
relativeThumbnails.isVisible = false
|
||||
sizeFilterItemArray = resources.getStringArray(R.array.filter_documents_size)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCurrentIsAllSelectStatus() {
|
||||
filterSelectedSetList.size.let {
|
||||
binding.tvSelectCounts.text = it.toString()
|
||||
@ -498,19 +558,20 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
//大小筛选
|
||||
filterSizeLayout.setOnClickListener {
|
||||
setItemSelect(it as LinearLayout, true)
|
||||
resources.getStringArray(R.array.filter_size).let { data ->
|
||||
sizeFilterItemArray.let { data ->
|
||||
filterSizePopupWindows = filterSizePopupWindows ?: FilterPopupWindows(
|
||||
this@PhotoSortingActivity,
|
||||
data,
|
||||
0,
|
||||
{ clickValue ->
|
||||
titleSize.text = clickValue
|
||||
when (clickValue) {
|
||||
data[0] -> filterSize = FILTER_SIZE_ALL
|
||||
data[1] -> filterSize = FILTER_SIZE_1
|
||||
data[2] -> filterSize = FILTER_SIZE_5
|
||||
data[3] -> filterSize = FILTER_SIZE_OVER_5
|
||||
}
|
||||
filterSize = clickValue
|
||||
// when (clickValue) {
|
||||
// data[0] -> filterSize = clickValue
|
||||
// data[1] -> filterSize = FILTER_SIZE_1
|
||||
// data[2] -> filterSize = FILTER_SIZE_5
|
||||
// data[3] -> filterSize = FILTER_SIZE_OVER_5
|
||||
// }
|
||||
startFilter()
|
||||
}) {
|
||||
setItemSelect(it, false)
|
||||
@ -578,48 +639,61 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行筛选结果
|
||||
* 执行筛选结果 todo
|
||||
*/
|
||||
private fun startFilter() {
|
||||
Common.showLog("--------------开始筛选")
|
||||
|
||||
val filterSizeCovert = filterSizeCovert(scanType, filterSize)
|
||||
when (binding.recyclerView.adapter) {
|
||||
//当前是时间排序
|
||||
is PhotoDisplayDateAdapter -> {
|
||||
//确定当前排序
|
||||
val list = if (sortReverse) sortByDateReverse else sortedByDatePositive
|
||||
val filterSizeCovert = filterSizeCovert(filterSize)
|
||||
list.filterWithinDateRange(
|
||||
filterDate,
|
||||
startDate = if (filterDate == FILTER_DATE_CUSTOMER) filterStartDate else null,
|
||||
endDate = if (filterDate == FILTER_DATE_CUSTOMER) filterEndDate else null
|
||||
)
|
||||
.filterBySize(filterSizeCovert.first, filterSizeCovert.second)
|
||||
.let { currentList ->
|
||||
checkRefreshDisPlaySelected(list1 = currentList)
|
||||
dateAdapter?.resetAllValue(null)
|
||||
dateAdapter?.setData(currentList)
|
||||
resetCurrentDateList(currentList)
|
||||
).run {
|
||||
when (scanType) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo, VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
filterBySize(filterSizeCovert.first, filterSizeCovert.second)
|
||||
}
|
||||
|
||||
else -> {
|
||||
filterByDuration(filterSizeCovert.first, filterSizeCovert.second)
|
||||
}
|
||||
}
|
||||
|
||||
}.let { currentList ->
|
||||
checkRefreshDisPlaySelected(list1 = currentList)
|
||||
dateAdapter?.resetAllValue(null)
|
||||
dateAdapter?.setData(currentList)
|
||||
resetCurrentDateList(currentList)
|
||||
}
|
||||
|
||||
}
|
||||
//当前是大小排序
|
||||
is PhotoDisplayDateChildAdapter -> {
|
||||
val list = if (sortReverse) sortBySizeBigToSmall else sortBySizeSmallToBig
|
||||
val filterSizeCovert = filterSizeCovert(filterSize)
|
||||
list.filterWithinDateRangeList(
|
||||
filterDate,
|
||||
startDate = if (filterDate == FILTER_DATE_CUSTOMER) filterStartDate else null,
|
||||
endDate = if (filterDate == FILTER_DATE_CUSTOMER) filterEndDate else null
|
||||
)
|
||||
.filterBySizeList(filterSizeCovert.first, filterSizeCovert.second)
|
||||
.let { currentList ->
|
||||
checkRefreshDisPlaySelected(list2 = currentList)
|
||||
sizeSortAdapter?.setData(currentList)
|
||||
resetCurrentSizeList(currentList)
|
||||
|
||||
|
||||
).run {
|
||||
when (scanType) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo, VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
filterBySizeList(filterSizeCovert.first, filterSizeCovert.second)
|
||||
}
|
||||
else -> {
|
||||
filterByDurationList(filterSizeCovert.first, filterSizeCovert.second)
|
||||
}
|
||||
}
|
||||
}.let { currentList ->
|
||||
checkRefreshDisPlaySelected(list2 = currentList)
|
||||
sizeSortAdapter?.setData(currentList)
|
||||
resetCurrentSizeList(currentList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -651,15 +725,44 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
}
|
||||
|
||||
|
||||
private fun filterSizeCovert(filterSize: Int): Pair<Long, Long> {
|
||||
return when (filterSize) {
|
||||
FILTER_SIZE_ALL -> Pair(-1L, -1L)
|
||||
FILTER_SIZE_1 -> Pair(0L, 1.mbToBytes())
|
||||
FILTER_SIZE_5 -> Pair(1.mbToBytes(), 5.mbToBytes())
|
||||
FILTER_SIZE_OVER_5 -> Pair(5.mbToBytes(), Long.MAX_VALUE)
|
||||
else -> Pair(-1L, -1L)
|
||||
private fun filterSizeCovert(scanType: Int, filterSize: String): Pair<Long, Long> {
|
||||
when (scanType) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo -> {
|
||||
val stringArray = resources.getStringArray(R.array.filter_size_photo)
|
||||
return when (filterSize) {
|
||||
stringArray[0] -> Pair(-1L, -1L)
|
||||
stringArray[1] -> Pair(0L, 1.mbToBytes())
|
||||
stringArray[2] -> Pair(1.mbToBytes(), 5.mbToBytes())
|
||||
stringArray[3] -> Pair(5.mbToBytes(), Long.MAX_VALUE)
|
||||
else -> Pair(-1L, -1L)
|
||||
}
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video, VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
val stringArray = resources.getStringArray(R.array.filter_duration_video_audio)
|
||||
return when (filterSize) {
|
||||
stringArray[0] -> Pair(-1L, -1L)
|
||||
stringArray[1] -> Pair(0L, 5.minutesToMillisecond())
|
||||
stringArray[2] -> Pair(5.minutesToMillisecond(), 20.minutesToMillisecond())
|
||||
stringArray[3] -> Pair(20.minutesToMillisecond(), 60.minutesToMillisecond())
|
||||
stringArray[4] -> Pair(60.minutesToMillisecond(), Long.MAX_VALUE)
|
||||
else -> Pair(-1L, -1L)
|
||||
}
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
val stringArray = resources.getStringArray(R.array.filter_documents_size)
|
||||
return when (filterSize) {
|
||||
stringArray[0] -> Pair(-1L, -1L)
|
||||
stringArray[1] -> Pair(0L, 500.kbToBytes())
|
||||
stringArray[2] -> Pair(500.kbToBytes(), 1.mbToBytes())
|
||||
stringArray[3] -> Pair(1.mbToBytes(), Long.MAX_VALUE)
|
||||
else -> Pair(-1L, -1L)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Pair(-1L, -1L)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -727,7 +830,6 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 删除或者恢复完成
|
||||
* @param type 0 恢复 1 删除
|
||||
|
||||
@ -3,6 +3,7 @@ package com.ux.video.file.filerecovery.photo
|
||||
import java.io.File
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.ux.video.file.filerecovery.utils.Common
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@ -17,7 +18,7 @@ data class ResultPhotosFiles(
|
||||
val targetFile: File?
|
||||
get() = path?.let { File(it) }
|
||||
|
||||
//是否为缩略图文件(宽高任一小于 256)
|
||||
//是否为缩略图文件(宽高任一小于 256)
|
||||
val isThumbnail: Boolean
|
||||
get() {
|
||||
val parts = resolution.lowercase().split("*").mapNotNull {
|
||||
@ -29,4 +30,10 @@ data class ResultPhotosFiles(
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
//音视频时长
|
||||
val duration: Long
|
||||
get() {
|
||||
return Common.getMediaDuration(path.toString()) }
|
||||
}
|
||||
|
||||
@ -2,16 +2,14 @@ package com.ux.video.file.filerecovery.result
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.ux.video.file.filerecovery.R
|
||||
import com.ux.video.file.filerecovery.base.BaseActivity
|
||||
import com.ux.video.file.filerecovery.databinding.ActivityScanResultDisplayBinding
|
||||
import com.ux.video.file.filerecovery.photo.PhotoSortingActivity
|
||||
import com.ux.video.file.filerecovery.photo.ResultPhotos
|
||||
import com.ux.video.file.filerecovery.result.ScanningActivity
|
||||
import com.ux.video.file.filerecovery.photo.ResultPhotosFiles
|
||||
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
|
||||
@ -22,17 +20,16 @@ import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_documents
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_video
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.getParcelableArrayListExtraCompat
|
||||
import com.ux.video.file.filerecovery.utils.ScanManager
|
||||
import com.ux.video.file.filerecovery.utils.ScanRepository
|
||||
|
||||
/**
|
||||
* 扫描结果汇总展示
|
||||
*/
|
||||
class ScanResultDisplayActivity : BaseActivity<ActivityScanResultDisplayBinding>() {
|
||||
private var scanResultAdapter: ScanResultAdapter? = null
|
||||
private var scanType: Int = VALUE_SCAN_TYPE_photo
|
||||
private var exitDialog: ExitDialogFragment? = null
|
||||
|
||||
private var list: ArrayList<ResultPhotos>? = null
|
||||
|
||||
companion object {
|
||||
val KEY_SCAN_RESULT = "scan_result"
|
||||
|
||||
@ -43,50 +40,16 @@ class ScanResultDisplayActivity : BaseActivity<ActivityScanResultDisplayBinding>
|
||||
|
||||
override fun initView() {
|
||||
super.initView()
|
||||
val list: ArrayList<ResultPhotos>? =
|
||||
intent.getParcelableArrayListExtraCompat(KEY_SCAN_RESULT)
|
||||
scanResultAdapter = ScanResultAdapter(this@ScanResultDisplayActivity) { folderLists ->
|
||||
startActivity(
|
||||
Intent(
|
||||
this@ScanResultDisplayActivity,
|
||||
PhotoSortingActivity::class.java
|
||||
).apply {
|
||||
putParcelableArrayListExtra(
|
||||
PhotoSortingActivity.KEY_PHOTO_FOLDER_FILE,
|
||||
folderLists
|
||||
)
|
||||
})
|
||||
}
|
||||
binding.recyclerResult.run {
|
||||
adapter = scanResultAdapter
|
||||
layoutManager = LinearLayoutManager(this@ScanResultDisplayActivity)
|
||||
}
|
||||
list?.let {
|
||||
binding.run {
|
||||
textDirCount.text = it.size.toString()
|
||||
val sumOf = it.sumOf { it.allFiles.size }
|
||||
textAllCounts.text = sumOf.toString()
|
||||
}
|
||||
scanResultAdapter?.setData(it)
|
||||
}
|
||||
list = intent.getParcelableArrayListExtraCompat(KEY_SCAN_RESULT)
|
||||
scanType = intent.getIntExtra(KEY_SCAN_TYPE, VALUE_SCAN_TYPE_photo)
|
||||
setSelectTypeTitle(scanType)
|
||||
|
||||
|
||||
// ScanRepository.instance.photoResults.observe(this@ScanResultDisplayActivity) {
|
||||
// binding.run {
|
||||
// textDirCount.text = it.size.toString()
|
||||
// val sumOf = it.sumOf { it.allFiles.size }
|
||||
// textAllCounts.text = sumOf.toString()
|
||||
// }
|
||||
// scanResultAdapter?.setData(it)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
scanType = intent.getIntExtra(KEY_SCAN_TYPE, VALUE_SCAN_TYPE_photo)
|
||||
setSelectTypeTitle(scanType)
|
||||
binding.imageViewBack.setOnClickListener { dealExit() }
|
||||
|
||||
onBackPressedDispatcher.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
@ -94,36 +57,96 @@ class ScanResultDisplayActivity : BaseActivity<ActivityScanResultDisplayBinding>
|
||||
dealExit()
|
||||
}
|
||||
})
|
||||
|
||||
binding.run {
|
||||
val myAdapter = when (scanType) {
|
||||
VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio, VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
bottomLayout.setBackgroundResource(R.drawable.bg_rectangle_white_top_20)
|
||||
ScanResultDocumentsAdapter(
|
||||
this@ScanResultDisplayActivity,
|
||||
scanType
|
||||
) { folderLists ->
|
||||
goSort(folderLists)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
bottomLayout.setBackgroundResource(0)
|
||||
ScanResultPhotoAdapter(
|
||||
this@ScanResultDisplayActivity,
|
||||
scanType
|
||||
) { folderLists ->
|
||||
goSort(folderLists)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}.apply {
|
||||
list?.let {
|
||||
textDirCount.text = it.size.toString()
|
||||
val sumOf = it.sumOf { it.allFiles.size }
|
||||
textAllCounts.text = sumOf.toString()
|
||||
setData(it)
|
||||
}
|
||||
}
|
||||
recyclerResult.run {
|
||||
adapter = myAdapter
|
||||
layoutManager = LinearLayoutManager(this@ScanResultDisplayActivity)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun dealExit(){
|
||||
exitDialog = exitDialog?:ExitDialogFragment(){
|
||||
private fun dealExit() {
|
||||
exitDialog = exitDialog ?: ExitDialogFragment() {
|
||||
finish()
|
||||
}
|
||||
exitDialog?.show(supportFragmentManager,"")
|
||||
exitDialog?.show(supportFragmentManager, "")
|
||||
}
|
||||
|
||||
private fun setSelectTypeTitle(fileType: Int) {
|
||||
binding.run {
|
||||
when (fileType) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo -> {
|
||||
title.text = getString(R.string.photo_title)
|
||||
textFileType.text = getString(R.string.text_photos)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video -> {
|
||||
title.text = getString(R.string.video_title)
|
||||
textFileType.text = getString(R.string.text_videos)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
title.text = getString(R.string.audio_title)
|
||||
textFileType.text = getString(R.string.text_audios)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_documents, VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
title.text = getString(R.string.document_title)
|
||||
textFileType.text = getString(R.string.text_documents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun goSort(list: ArrayList<ResultPhotosFiles>) {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@ScanResultDisplayActivity,
|
||||
PhotoSortingActivity::class.java
|
||||
).apply {
|
||||
putExtra(KEY_SCAN_TYPE, scanType)
|
||||
putParcelableArrayListExtra(
|
||||
PhotoSortingActivity.KEY_PHOTO_FOLDER_FILE,
|
||||
list
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.ux.video.file.filerecovery.result
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.ux.video.file.filerecovery.R
|
||||
import com.ux.video.file.filerecovery.base.BaseAdapter
|
||||
import com.ux.video.file.filerecovery.databinding.ScanResultAdapterBinding
|
||||
import com.ux.video.file.filerecovery.databinding.ScanResultDocumentsAdapterBinding
|
||||
import com.ux.video.file.filerecovery.photo.ResultPhotos
|
||||
import com.ux.video.file.filerecovery.photo.ResultPhotosFiles
|
||||
import com.ux.video.file.filerecovery.utils.Common
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.dpToPx
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 文件或者音频的扫描结果汇总适配器
|
||||
*/
|
||||
class ScanResultDocumentsAdapter(
|
||||
mContext: Context,
|
||||
var type: Int,
|
||||
var onClickItem: (allFiles: ArrayList<ResultPhotosFiles>) -> Unit
|
||||
) :
|
||||
BaseAdapter<ResultPhotos, ScanResultDocumentsAdapterBinding>(mContext) {
|
||||
override fun getViewBinding(parent: ViewGroup): ScanResultDocumentsAdapterBinding =
|
||||
ScanResultDocumentsAdapterBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindItem(
|
||||
holder: VHolder<ScanResultDocumentsAdapterBinding>,
|
||||
item: ResultPhotos
|
||||
) {
|
||||
|
||||
holder.vb.run {
|
||||
item.run {
|
||||
relativeLayout.setOnClickListener { onClickItem(allFiles) }
|
||||
textDirName.text = dirName
|
||||
textFileCounts.text = allFiles.size.toString()
|
||||
when(type){
|
||||
Common.VALUE_SCAN_TYPE_audio, Common.VALUE_SCAN_TYPE_deleted_audio->{
|
||||
icon.setImageResource(R.drawable.icon_folder_audio)
|
||||
}
|
||||
Common.VALUE_SCAN_TYPE_documents, Common.VALUE_SCAN_TYPE_deleted_documents->{
|
||||
icon.setImageResource(R.drawable.icon_folder_documents)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -16,8 +16,9 @@ import com.ux.video.file.filerecovery.photo.ResultPhotosFiles
|
||||
import com.ux.video.file.filerecovery.utils.ExtendFunctions.dpToPx
|
||||
import java.io.File
|
||||
|
||||
class ScanResultAdapter(
|
||||
class ScanResultPhotoAdapter(
|
||||
mContext: Context,
|
||||
var type: Int,
|
||||
var onClickItem: (allFiles: ArrayList<ResultPhotosFiles>) -> Unit
|
||||
) :
|
||||
BaseAdapter<ResultPhotos, ScanResultAdapterBinding>(mContext) {
|
||||
@ -1,8 +1,11 @@
|
||||
package com.ux.video.file.filerecovery.result
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Environment
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.ux.video.file.filerecovery.R
|
||||
import com.ux.video.file.filerecovery.base.BaseActivity
|
||||
@ -26,20 +29,10 @@ import com.ux.video.file.filerecovery.utils.ScanState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
|
||||
class ScanningActivity : BaseActivity<ActivityScanningBinding>() {
|
||||
|
||||
companion object {
|
||||
// val KEY_SCAN_TYPE = "scan_type"
|
||||
// val VALUE_SCAN_TYPE_photo = 0
|
||||
// val VALUE_SCAN_TYPE_deleted_photo = 1
|
||||
// val VALUE_SCAN_TYPE_video = 2
|
||||
// val VALUE_SCAN_TYPE_deleted_video = 3
|
||||
// val VALUE_SCAN_TYPE_audio = 4
|
||||
// val VALUE_SCAN_TYPE_deleted_audio = 5
|
||||
// val VALUE_SCAN_TYPE_documents = 6
|
||||
// val VALUE_SCAN_TYPE_deleted_documents = 7
|
||||
}
|
||||
|
||||
private var scanType: Int = VALUE_SCAN_TYPE_photo
|
||||
override fun inflateBinding(inflater: LayoutInflater): ActivityScanningBinding =
|
||||
@ -53,7 +46,7 @@ class ScanningActivity : BaseActivity<ActivityScanningBinding>() {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_documents -> scanAll()
|
||||
VALUE_SCAN_TYPE_deleted_photo, VALUE_SCAN_TYPE_deleted_video, VALUE_SCAN_TYPE_deleted_audio, VALUE_SCAN_TYPE_deleted_documents -> scanDeleted()
|
||||
}
|
||||
binding.scanProgress.setCenterImage(R.drawable.im_photo_center_image)
|
||||
|
||||
binding.imageViewBack.setOnClickListener { finish() }
|
||||
|
||||
}
|
||||
@ -65,41 +58,49 @@ class ScanningActivity : BaseActivity<ActivityScanningBinding>() {
|
||||
VALUE_SCAN_TYPE_photo -> {
|
||||
title.text = getString(R.string.photo_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_photos)
|
||||
scanProgress.setCenterImage(R.drawable.im_photo_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_deleted_photo -> {
|
||||
title.text = getString(R.string.photo_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_delete_photos)
|
||||
scanProgress.setCenterImage(R.drawable.im_photo_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_video -> {
|
||||
title.text = getString(R.string.video_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_videos)
|
||||
scanProgress.setCenterImage(R.drawable.im_video_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_deleted_video -> {
|
||||
title.text = getString(R.string.video_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_delete_videos)
|
||||
scanProgress.setCenterImage(R.drawable.im_video_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_audio -> {
|
||||
title.text = getString(R.string.audio_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_audios)
|
||||
scanProgress.setCenterImage(R.drawable.im_audio_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_deleted_audio -> {
|
||||
title.text = getString(R.string.audio_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_delete_audios)
|
||||
scanProgress.setCenterImage(R.drawable.im_audio_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_documents -> {
|
||||
title.text = getString(R.string.document_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_documents)
|
||||
scanProgress.setCenterImage(R.drawable.im_documents_center_image)
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_deleted_documents -> {
|
||||
title.text = getString(R.string.document_title)
|
||||
tvScanDescribe.text = getString(R.string.describe_delete_documents)
|
||||
scanProgress.setCenterImage(R.drawable.im_documents_center_image)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,15 +111,18 @@ class ScanningActivity : BaseActivity<ActivityScanningBinding>() {
|
||||
private fun scanAll() {
|
||||
val total = 800
|
||||
lifecycleScope.launch {
|
||||
val root = Environment.getExternalStorageDirectory()
|
||||
ScanManager.scanAllDocuments(this@ScanningActivity,root, type = scanType).flowOn(Dispatchers.IO).collect {
|
||||
when (it) {
|
||||
is ScanState.Progress -> {
|
||||
updateProgress(it)
|
||||
}
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
val root = Environment.getExternalStorageDirectory()
|
||||
ScanManager.scanAllDocuments(this@ScanningActivity, root, type = scanType)
|
||||
.flowOn(Dispatchers.IO).collect {
|
||||
when (it) {
|
||||
is ScanState.Progress -> {
|
||||
updateProgress(it)
|
||||
}
|
||||
|
||||
is ScanState.Complete -> {
|
||||
updateComplete(it)
|
||||
is ScanState.Complete -> {
|
||||
updateComplete(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,20 +133,23 @@ class ScanningActivity : BaseActivity<ActivityScanningBinding>() {
|
||||
|
||||
private fun scanDeleted() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
val root = Environment.getExternalStorageDirectory()
|
||||
ScanManager.scanHiddenPhotoAsync(this@ScanningActivity, root, type = scanType)
|
||||
.flowOn(Dispatchers.IO).collect {
|
||||
when (it) {
|
||||
is ScanState.Progress -> {
|
||||
updateProgress(it)
|
||||
|
||||
val root = Environment.getExternalStorageDirectory()
|
||||
ScanManager.scanHiddenPhotoAsync(this@ScanningActivity,root, type = scanType).flowOn(Dispatchers.IO).collect {
|
||||
when (it) {
|
||||
is ScanState.Progress -> {
|
||||
updateProgress(it)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
is ScanState.Complete -> {
|
||||
updateComplete(it)
|
||||
is ScanState.Complete -> {
|
||||
updateComplete(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -166,27 +173,32 @@ class ScanningActivity : BaseActivity<ActivityScanningBinding>() {
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun updateComplete(scanState: ScanState.Complete) {
|
||||
binding.scanProgress.setProgress(100)
|
||||
scanState.let {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@ScanningActivity,
|
||||
ScanResultDisplayActivity::class.java
|
||||
).apply {
|
||||
putParcelableArrayListExtra(
|
||||
ScanResultDisplayActivity.KEY_SCAN_RESULT,
|
||||
it.result
|
||||
)
|
||||
})
|
||||
ScanManager.showLog(
|
||||
"HiddenScan",
|
||||
"完成: ${it.result.size}"
|
||||
)
|
||||
|
||||
binding.run {
|
||||
scanProgress.setProgress(100)
|
||||
scanState.let {
|
||||
val size = it.result.size
|
||||
if (size == 0) {
|
||||
tvScanDescribe.text.let {
|
||||
tvEmptyTypeFile.text = "0 $it"
|
||||
tvSorry.text = getString(R.string.not_found,it)
|
||||
}
|
||||
relativeScanFinishedEmpty.isVisible = true
|
||||
linearCounts.isVisible = false
|
||||
}else{
|
||||
finish()
|
||||
startActivity(Intent(this@ScanningActivity, ScanResultDisplayActivity::class.java).apply {
|
||||
putParcelableArrayListExtra(
|
||||
ScanResultDisplayActivity.KEY_SCAN_RESULT,
|
||||
it.result
|
||||
)
|
||||
putExtra(KEY_SCAN_TYPE, scanType)
|
||||
})
|
||||
}
|
||||
ScanManager.showLog("HiddenScan", "完成: ${it.result.size}")
|
||||
}
|
||||
}
|
||||
finish()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
package com.ux.video.file.filerecovery.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.icu.text.SimpleDateFormat
|
||||
import android.icu.util.Calendar
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
@ -265,6 +267,36 @@ object Common {
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getMediaDuration(filePath: String): Long {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
return try {
|
||||
retriever.setDataSource(filePath)
|
||||
val durationStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
||||
durationStr?.toLongOrNull() ?: 0L // 单位:毫秒
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
0L
|
||||
} finally {
|
||||
retriever.release()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun formatDuration(ms: Long): String {
|
||||
val totalSeconds = ms / 1000
|
||||
val hours = totalSeconds / 3600
|
||||
val minutes = (totalSeconds % 3600) / 60
|
||||
val seconds = totalSeconds % 60
|
||||
|
||||
return if (hours > 0) {
|
||||
String.format("%02d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
String.format("%02d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getFormatDate(time: Long): String {
|
||||
return dateFormat.format(Date(time))
|
||||
}
|
||||
|
||||
@ -40,21 +40,6 @@ object ExtendFunctions {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按时间筛选:最近 N 个月
|
||||
*/
|
||||
// fun List<ResultPhotosFiles>.filterWithinMonthsList(months: Int): List<ResultPhotosFiles> {
|
||||
// if (months == -1) return this
|
||||
// val today = Calendar.getInstance()
|
||||
// val monthsAgo = Calendar.getInstance().apply {
|
||||
// add(Calendar.MONTH, -months)
|
||||
// }
|
||||
// return this.filter {
|
||||
// val cal = Calendar.getInstance().apply { timeInMillis = it.lastModified }
|
||||
// !cal.before(monthsAgo) && !cal.after(today)
|
||||
// }
|
||||
// }
|
||||
|
||||
fun List<ResultPhotosFiles>.filterWithinDateRangeList(
|
||||
months: Int = -1,
|
||||
startDate: Date? = null,
|
||||
@ -64,10 +49,9 @@ object ExtendFunctions {
|
||||
val today = Calendar.getInstance()
|
||||
|
||||
return when {
|
||||
// ✅ 1. -1 表示不过滤,返回全部
|
||||
|
||||
months == -1 -> this
|
||||
|
||||
// ✅ 2. 0 表示仅根据 startDate / endDate 筛选
|
||||
months == 0 -> this.filter { file ->
|
||||
val date = Date(file.lastModified)
|
||||
when {
|
||||
@ -78,7 +62,6 @@ object ExtendFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 3. 其他情况:按“最近 N 个月”筛选
|
||||
else -> {
|
||||
val monthsAgo = Calendar.getInstance().apply {
|
||||
add(Calendar.MONTH, -months)
|
||||
@ -95,32 +78,7 @@ object ExtendFunctions {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 按文件大小筛选:区间 [minSize, maxSize]
|
||||
*/
|
||||
fun List<ResultPhotosFiles>.filterBySizeList(
|
||||
minSize: Long,
|
||||
maxSize: Long
|
||||
): List<ResultPhotosFiles> {
|
||||
if (minSize == -1L) return this
|
||||
return this.filter { it.size in minSize..maxSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间筛选:最近 N 个月
|
||||
*/
|
||||
// fun List<Pair<String, List<ResultPhotosFiles>>>.filterWithinMonths(months: Int): List<Pair<String, List<ResultPhotosFiles>>> {
|
||||
// if (months == -1) return this
|
||||
// val sdf = Common.dateFormat
|
||||
// val today = Calendar.getInstance()
|
||||
// val monthsAgo = Calendar.getInstance().apply {
|
||||
// add(Calendar.MONTH, -months)
|
||||
// }
|
||||
// return this.filter { (dayStr, _) ->
|
||||
// val day = sdf.parse(dayStr)
|
||||
// day != null && !day.before(monthsAgo.time) && !day.after(today.time)
|
||||
// }
|
||||
// }
|
||||
fun List<Pair<String, List<ResultPhotosFiles>>>.filterWithinDateRange(
|
||||
months: Int = -1,
|
||||
startDate: Date? = null,
|
||||
@ -136,10 +94,10 @@ object ExtendFunctions {
|
||||
}
|
||||
|
||||
return when {
|
||||
// -1 表示不过滤,返回全部
|
||||
|
||||
months == -1 -> this
|
||||
|
||||
// 0 表示只用日期范围过滤
|
||||
|
||||
months == 0 -> this.filter { (dayStr, _) ->
|
||||
val day = sdf.parse(dayStr) ?: return@filter false
|
||||
when {
|
||||
@ -150,22 +108,37 @@ object ExtendFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
// 其他情况:按“最近 N 个月”过滤
|
||||
|
||||
else -> this.filter { (dayStr, _) ->
|
||||
val day = sdf.parse(dayStr) ?: return@filter false
|
||||
!day.before(monthsAgo.time) && !day.after(today.time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 按文件大小筛选:区间 [minSize, maxSize]
|
||||
*/
|
||||
fun List<ResultPhotosFiles>.filterBySizeList(
|
||||
minSize: Long,
|
||||
maxSize: Long
|
||||
): List<ResultPhotosFiles> {
|
||||
if (minSize == -1L) return this
|
||||
return this.filter { it.size in minSize..maxSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组数据:按大小筛选
|
||||
* 按文件大小筛选:区间 [minSize, maxSize]
|
||||
*/
|
||||
fun List<ResultPhotosFiles>.filterByDurationList(
|
||||
minSize: Long,
|
||||
maxSize: Long
|
||||
): List<ResultPhotosFiles> {
|
||||
if (minSize == -1L) return this
|
||||
return this.filter { it.duration in minSize..maxSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组数据:按大小筛选 ,图片和文件筛选文件大小
|
||||
*/
|
||||
fun List<Pair<String, List<ResultPhotosFiles>>>.filterBySize(
|
||||
minSize: Long,
|
||||
@ -177,10 +150,34 @@ object ExtendFunctions {
|
||||
if (filtered.isNotEmpty()) date to filtered else null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组数据:按大小筛选 ,音视频筛选时长
|
||||
*/
|
||||
fun List<Pair<String, List<ResultPhotosFiles>>>.filterByDuration(
|
||||
minSize: Long,
|
||||
maxSize: Long
|
||||
): List<Pair<String, List<ResultPhotosFiles>>> {
|
||||
if (minSize == -1L) return this
|
||||
return this.mapNotNull { (date, files) ->
|
||||
val filtered = files.filter { it.duration in minSize..maxSize }
|
||||
if (filtered.isNotEmpty()) date to filtered else null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Int.mbToBytes(): Long {
|
||||
return this * 1000L * 1000L
|
||||
}
|
||||
|
||||
fun Int.kbToBytes(): Long {
|
||||
return this * 1000L
|
||||
}
|
||||
|
||||
fun Int.minutesToMillisecond(): Long {
|
||||
return this * 60 * 1000L
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除掉缩略图后的数据
|
||||
*/
|
||||
|
||||
@ -3,6 +3,7 @@ package com.ux.video.file.filerecovery.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
@ -22,6 +23,8 @@ import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_photo
|
||||
import com.ux.video.file.filerecovery.utils.Common.VALUE_SCAN_TYPE_video
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
@ -63,9 +66,12 @@ object ScanManager {
|
||||
val result = mutableMapOf<String, MutableList<File>>()
|
||||
var fileCount = 0
|
||||
suspend fun scanDocuments(dir: File, depth: Int) {
|
||||
val context = currentCoroutineContext()
|
||||
|
||||
if (!dir.exists() || !dir.isDirectory) return
|
||||
if (depth > maxDepth || fileCount >= maxFiles) return
|
||||
dir.listFiles()?.forEach { file ->
|
||||
context.ensureActive()
|
||||
if (file.isDirectory) {
|
||||
scanDocuments(file, depth + 1)
|
||||
} else {
|
||||
@ -107,11 +113,12 @@ object ScanManager {
|
||||
name = file.name,
|
||||
path = file.absolutePath,
|
||||
size = file.length(),
|
||||
sizeString = android.text.format.Formatter.formatFileSize(context, file.length()),
|
||||
sizeString = android.text.format.Formatter.formatFileSize(
|
||||
context,
|
||||
file.length()
|
||||
),
|
||||
lastModified = file.lastModified(),
|
||||
resolution = getImageSize(file).run {
|
||||
"$first*$second"
|
||||
}
|
||||
resolution = getResolution(type,file)
|
||||
)
|
||||
}
|
||||
ResultPhotos(dir, ArrayList(resultPhotosFilesList))
|
||||
@ -128,6 +135,25 @@ object ScanManager {
|
||||
return Pair(width, height)
|
||||
}
|
||||
|
||||
|
||||
fun getVideoResolution(filePath: String): Pair<Int, Int> {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
return try {
|
||||
retriever.setDataSource(filePath)
|
||||
val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
|
||||
?.toIntOrNull() ?: 0
|
||||
val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
|
||||
?.toIntOrNull() ?: 0
|
||||
width to height
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
0 to 0
|
||||
} finally {
|
||||
retriever.release()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 递归扫描隐藏目录下的有效图片(删除的图片)
|
||||
* @param maxDepth // 最大递归深度
|
||||
@ -141,6 +167,7 @@ object ScanManager {
|
||||
|
||||
val result = mutableMapOf<String, MutableList<File>>()
|
||||
var fileCount = 0
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
suspend fun scanDir(dir: File, depth: Int, insideHidden: Boolean = false) {
|
||||
if (!dir.exists() || !dir.isDirectory) return
|
||||
@ -192,11 +219,12 @@ object ScanManager {
|
||||
name = file.name,
|
||||
path = file.absolutePath,
|
||||
size = file.length(),
|
||||
sizeString = android.text.format.Formatter.formatFileSize(context, file.length()),
|
||||
sizeString = android.text.format.Formatter.formatFileSize(
|
||||
context,
|
||||
file.length()
|
||||
),
|
||||
lastModified = file.lastModified(),
|
||||
resolution = getImageSize(file).run {
|
||||
"$first*$second"
|
||||
}
|
||||
resolution = getResolution(type,file)
|
||||
)
|
||||
|
||||
}
|
||||
@ -217,6 +245,22 @@ object ScanManager {
|
||||
return file.length() // fallback
|
||||
}
|
||||
|
||||
private fun getResolution(type: Int,file: File): String {
|
||||
return when (type) {
|
||||
VALUE_SCAN_TYPE_photo, VALUE_SCAN_TYPE_deleted_photo -> {
|
||||
getImageSize(file).run {
|
||||
"$first*$second"
|
||||
}
|
||||
}
|
||||
|
||||
VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video -> getVideoResolution(file.path).run {
|
||||
"$first*$second"
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFormatFile(file: File, types: List<String>): Boolean {
|
||||
val ext = file.extension.lowercase()
|
||||
return types.contains(ext)
|
||||
|
||||
@ -0,0 +1,183 @@
|
||||
package com.ux.video.file.filerecovery.video
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.SeekBar
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import com.ux.video.file.filerecovery.R
|
||||
import com.ux.video.file.filerecovery.base.BaseActivity
|
||||
import com.ux.video.file.filerecovery.databinding.ActivityScanSelectTypeBinding
|
||||
import com.ux.video.file.filerecovery.databinding.ActivityVideoPlayBinding
|
||||
import com.ux.video.file.filerecovery.photo.PhotoInfoActivity
|
||||
import com.ux.video.file.filerecovery.photo.PhotoInfoActivity.Companion.KEY_CLICK_ITEM
|
||||
import com.ux.video.file.filerecovery.photo.RecoverOrDeleteManager
|
||||
import com.ux.video.file.filerecovery.photo.ResultPhotosFiles
|
||||
import com.ux.video.file.filerecovery.success.RecoverySuccessActivity
|
||||
import com.ux.video.file.filerecovery.utils.Common
|
||||
|
||||
class VideoPlayActivity : BaseActivity<ActivityVideoPlayBinding>() {
|
||||
|
||||
companion object {
|
||||
val KEY_DATA = "key_data"
|
||||
}
|
||||
|
||||
private lateinit var player: ExoPlayer
|
||||
private var myData: ResultPhotosFiles? = null
|
||||
private val updateHandler = Handler(Looper.getMainLooper())
|
||||
override fun inflateBinding(inflater: LayoutInflater): ActivityVideoPlayBinding =
|
||||
ActivityVideoPlayBinding.inflate(inflater)
|
||||
|
||||
override fun initView() {
|
||||
super.initView()
|
||||
}
|
||||
|
||||
override fun addPadding(): Boolean = false
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
myData = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra(KEY_DATA, ResultPhotosFiles::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
intent.getParcelableExtra(KEY_DATA)
|
||||
}
|
||||
initPlayer()
|
||||
binding.run {
|
||||
myData?.let { resultPhotosFiles->
|
||||
imageBack.setOnClickListener { finish() }
|
||||
playImage.setOnClickListener {
|
||||
if (player.playbackState == Player.STATE_ENDED) {
|
||||
player.seekTo(0)
|
||||
}
|
||||
if (!player.isPlaying) {
|
||||
player.play()
|
||||
it.isSelected = true
|
||||
} else {
|
||||
player.pause()
|
||||
it.isSelected = false
|
||||
}
|
||||
}
|
||||
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(
|
||||
seekBar: SeekBar?,
|
||||
progress: Int,
|
||||
fromUser: Boolean
|
||||
) {
|
||||
if (fromUser) {
|
||||
val newPosition = progress * player.duration / 100
|
||||
player.seekTo(newPosition)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {
|
||||
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar?) {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
startProgressUpdater()
|
||||
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 startProgressUpdater() {
|
||||
updateHandler.post(object : Runnable {
|
||||
override fun run() {
|
||||
if (player.isPlaying || player.isLoading) {
|
||||
val pos = player.currentPosition
|
||||
val dur = player.duration.takeIf { it > 0 } ?: 1L
|
||||
val progress = (pos * 100 / dur).toInt()
|
||||
binding.seekBar.progress = progress
|
||||
|
||||
binding.textTimeCurrent.text = Common.formatDuration(pos)
|
||||
binding.textTimeTotal.text = Common.formatDuration(dur)
|
||||
}
|
||||
updateHandler.postDelayed(this, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun initPlayer() {
|
||||
myData?.let {
|
||||
player = ExoPlayer.Builder(this).build()
|
||||
binding.playerView.player = player
|
||||
val mediaItem = MediaItem.fromUri(Uri.fromFile(it.targetFile))
|
||||
player.addListener(object : Player.Listener {
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
super.onPlaybackStateChanged(playbackState)
|
||||
when (playbackState) {
|
||||
Player.STATE_IDLE -> {
|
||||
|
||||
}
|
||||
|
||||
Player.STATE_BUFFERING -> {
|
||||
|
||||
}
|
||||
|
||||
Player.STATE_READY -> {
|
||||
|
||||
}
|
||||
|
||||
Player.STATE_ENDED -> {
|
||||
binding.playImage.isSelected = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
player.setMediaItem(mediaItem)
|
||||
player.prepare()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun complete(number: Int, type: Int) {
|
||||
finish()
|
||||
startActivity(Intent(this@VideoPlayActivity, RecoverySuccessActivity::class.java).apply {
|
||||
putExtra(RecoverySuccessActivity.KEY_SUCCESS_COUNT, number)
|
||||
putExtra(RecoverySuccessActivity.KEY_SUCCESS_TYPE, type)
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/res/drawable/back_white.png
Normal file
|
After Width: | Height: | Size: 497 B |
BIN
app/src/main/res/drawable/icon_finished.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
app/src/main/res/drawable/icon_folder_audio.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/drawable/icon_folder_documents.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable/icon_info_pause.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/src/main/res/drawable/icon_info_play.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
app/src/main/res/drawable/icon_item_audio_play.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable/icon_small_audio.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/drawable/icon_type_photo.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/drawable/icon_type_video.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/drawable/im_audio_center_image.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
app/src/main/res/drawable/im_documents_center_image.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/src/main/res/drawable/im_video_center_image.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
7
app/src/main/res/drawable/seekbar_thumb.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size android:width="8dp" android:height="16dp"/>
|
||||
<corners android:radius="20dp"/>
|
||||
<solid android:color="@color/white"/>
|
||||
</shape>
|
||||
25
app/src/main/res/drawable/seekbar_video_play.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background" android:height="4dp" android:gravity="center_vertical">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="100dp" />
|
||||
<size android:height="4dp" />
|
||||
<solid android:color="@color/bg_seekbar_video_play" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:id="@android:id/secondaryProgress" android:height="4dp" android:gravity="center_vertical">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="100dp" />
|
||||
<size android:height="4dp" />
|
||||
<solid android:color="@color/main_sub_title" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:id="@android:id/progress" android:height="4dp" android:gravity="center_vertical">
|
||||
<clip>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="100dp" />
|
||||
<size android:height="4dp" />
|
||||
<solid android:color="@color/main_text_blue" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
||||
6
app/src/main/res/drawable/selector_play_button.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/icon_info_pause" android:state_selected="true" />
|
||||
<item android:drawable="@drawable/icon_info_play" android:state_selected="false" />
|
||||
|
||||
</selector>
|
||||
@ -48,13 +48,30 @@
|
||||
android:padding="16dp"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="320dp" />
|
||||
android:id="@+id/frame_image"
|
||||
android:layout_height="320dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="320dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/im_play"
|
||||
android:layout_width="76dp"
|
||||
android:layout_height="76dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/icon_info_play" />
|
||||
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@ -80,6 +97,33 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/type"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:gravity="end"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_path"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
@ -105,6 +149,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_resolution"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
@ -130,6 +175,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_date"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
@ -154,6 +200,58 @@
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/size"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:gravity="end"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_duration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="11dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/duration"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_duration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:gravity="end"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
@ -52,13 +52,13 @@
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/title_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/date"
|
||||
android:ellipsize="end"
|
||||
android:maxWidth="85dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:id="@+id/title_date"
|
||||
android:text="@string/date"
|
||||
android:textColor="@color/selector_black_blue"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
@ -81,13 +81,13 @@
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/title_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/size"
|
||||
android:ellipsize="end"
|
||||
android:maxWidth="85dp"
|
||||
android:maxLines="1"
|
||||
android:id="@+id/title_size"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/size"
|
||||
android:textColor="@color/selector_black_blue"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
@ -125,48 +125,55 @@
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/im_sort"
|
||||
android:layout_width="47dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_alignTop="@id/filter_date_layout"
|
||||
android:layout_alignBottom="@id/filter_date_layout"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/im_sort"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:src="@drawable/icon_sort" />
|
||||
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_thumbnail_counts"
|
||||
android:layout_width="wrap_content"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/filter_date_layout"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/hide_thumbnails"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
android:id="@+id/relative_thumbnails"
|
||||
android:layout_below="@id/filter_date_layout">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/tv_thumbnail_counts"
|
||||
android:layout_alignStart="@id/tv_thumbnail_counts"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/hide_thumbnails_describe"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="12sp" />
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_thumbnail_counts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/hide_thumbnails"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/tv_thumbnail_counts"
|
||||
android:layout_alignStart="@id/tv_thumbnail_counts"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/hide_thumbnails_describe"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switch_hide_thumbnails"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:layout_alignTop="@id/tv_thumbnail_counts"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:thumbTint="@color/selector_switch_thumb_color"
|
||||
app:trackTint="@color/selector_switch_track_color" />
|
||||
</RelativeLayout>
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switch_hide_thumbnails"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:layout_alignTop="@id/tv_thumbnail_counts"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:thumbTint="@color/selector_switch_thumb_color"
|
||||
app:trackTint="@color/selector_switch_track_color" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
android:background="@color/white"
|
||||
android:orientation="vertical"
|
||||
tools:context=".result.ScanResultDisplayActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp"
|
||||
@ -99,11 +100,11 @@
|
||||
android:id="@+id/text_file_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:fontType="bold"
|
||||
android:text="photos"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:text="photos" />
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
@ -141,23 +142,31 @@
|
||||
android:id="@+id/text_dir"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:fontType="bold"
|
||||
android:text="Folders"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:text="Folders" />
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_result"
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottom_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp" />
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_rectangle_white_top_20"
|
||||
android:layout_marginTop="20dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_result"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingVertical="10dp"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
@ -34,67 +34,71 @@
|
||||
app:fontType="bold" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/color_bg"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CircleImageProgressView
|
||||
android:id="@+id/scan_progress"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="130dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="150dp"
|
||||
android:max="100"
|
||||
android:progress="10" />
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/linear_counts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/scan_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="30dp"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="150dp">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CircleImageProgressView
|
||||
android:id="@+id/scan_progress"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="130dp"
|
||||
android:max="100"
|
||||
android:progress="10"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_scan_current_counts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
android:gravity="end"
|
||||
android:text="10"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
app:fontType="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_scan_describe"
|
||||
app:layout_constraintHorizontal_weight="1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/scan_progress" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_scan_describe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="10"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
</LinearLayout>
|
||||
app:fontType="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="1"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_scan_current_counts"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_scan_current_counts" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linear_loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/linear_counts"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="100dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_pb"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:indeterminateTint="@color/main_title" />
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="103dp"
|
||||
android:indeterminateTint="@color/main_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_scan_current_counts" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:layout_width="wrap_content"
|
||||
@ -103,22 +107,80 @@
|
||||
android:text="@string/scan"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="20sp"
|
||||
app:fontType="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/loading_pb"
|
||||
app:layout_constraintStart_toEndOf="@id/loading_pb"
|
||||
app:layout_constraintTop_toTopOf="@id/loading_pb"
|
||||
app:layout_constraintVertical_bias="0.5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_scan_current_file_path"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignStart="@id/loading_pb"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="path"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintStart_toStartOf="@id/loading_pb"
|
||||
app:layout_constraintTop_toBottomOf="@id/loading_pb" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/relative_scan_finished_empty"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="220dp"
|
||||
android:src="@drawable/icon_finished" />
|
||||
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_finish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/icon"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/finished"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_empty_type_file"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/tv_finish"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="107dp"
|
||||
android:text="0"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/tv_sorry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/tv_empty_type_file"
|
||||
android:layout_alignStart="@id/tv_empty_type_file"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/not_found"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="12sp"
|
||||
app:fontType="regular" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_scan_current_file_path"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/linear_loading"
|
||||
android:layout_alignStart="@id/linear_loading"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="path"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
88
app/src/main/res/layout/activity_video_play.xml
Normal file
@ -0,0 +1,88 @@
|
||||
<?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"
|
||||
tools:context=".video.VideoPlayActivity">
|
||||
|
||||
|
||||
<androidx.media3.ui.PlayerView
|
||||
android:id="@+id/player_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:resize_mode="fill"
|
||||
app:use_controller="false" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_back"
|
||||
android:layout_width="45dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_marginTop="54dp"
|
||||
android:paddingHorizontal="15dp"
|
||||
android:paddingVertical="12dp"
|
||||
android:src="@drawable/back_white"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/layout_bottom">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_time_current"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="10sp"
|
||||
app:fontType="bold"
|
||||
tools:text="00:00" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seek_bar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_weight="1"
|
||||
android:max="100"
|
||||
android:progress="30"
|
||||
android:progressDrawable="@drawable/seekbar_video_play"
|
||||
android:splitTrack="false"
|
||||
android:thumb="@drawable/seekbar_thumb" />
|
||||
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_time_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="10sp"
|
||||
app:fontType="bold"
|
||||
tools:text="00:00" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/layout_bottom"
|
||||
layout="@layout/common_bottom_btn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="40dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_image"
|
||||
android:layout_width="110dp"
|
||||
android:layout_height="110dp"
|
||||
android:src="@drawable/selector_play_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -3,10 +3,10 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root_layout"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginTop="9dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp">
|
||||
android:layout_height="150dp"
|
||||
android:layout_marginTop="9dp"
|
||||
android:layout_marginEnd="10dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_thumbnail"
|
||||
@ -14,19 +14,33 @@
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_size"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingStart="6dp"
|
||||
android:background="@drawable/photo_size_bg"
|
||||
android:text="150kb"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="11sp"
|
||||
app:fontType="bold"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
android:layout_alignParentBottom="true">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="6dp"
|
||||
android:text="150kb"
|
||||
android:layout_centerVertical="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="11sp"
|
||||
app:fontType="bold"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_type"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@drawable/icon_type_photo" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<ImageView
|
||||
|
||||
@ -13,18 +13,33 @@
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_size"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@drawable/photo_size_bg"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="6dp"
|
||||
android:text="150kb"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
android:background="@drawable/photo_size_bg">
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingStart="6dp"
|
||||
android:text="150kb"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_type"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@drawable/icon_type_photo" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
<ImageView
|
||||
|
||||
81
app/src/main/res/layout/one_audio_documents_item.xml
Normal file
@ -0,0 +1,81 @@
|
||||
<?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="64dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_select"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
android:src="@drawable/selector_icon_checkmark_28dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="bottom"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold"
|
||||
app:layout_constraintBottom_toTopOf="@id/linear_duration"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_select"
|
||||
app:layout_constraintRight_toLeftOf="@id/image_play"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="aaaaaaaaaassssssssssssssssssssssssssssssssa" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linear_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="top"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="@id/text_name"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_name">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:src="@drawable/icon_small_audio" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="11sp"
|
||||
tools:text="aaaaaaaaaaa" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="11sp"
|
||||
tools:text="aaaaaaaaaaa" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_play"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/icon_item_audio_play"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
52
app/src/main/res/layout/scan_result_documents_adapter.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="46dp"
|
||||
android:id="@+id/relative_layout"
|
||||
android:paddingHorizontal="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/icon_folder_audio" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_dir_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_toEndOf="@id/icon"
|
||||
android:gravity="center"
|
||||
android:text="@string/allow"
|
||||
android:textColor="@color/main_title"
|
||||
android:textSize="16sp"
|
||||
app:fontType="bold"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.ux.video.file.filerecovery.utils.CustomTextView
|
||||
android:id="@+id/text_file_counts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:text="@string/allow"
|
||||
android:layout_toStartOf="@id/im_arrow"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:textColor="@color/main_sub_title"
|
||||
android:textSize="14sp"
|
||||
app:fontType="bold" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="7dp"
|
||||
android:layout_height="11dp"
|
||||
android:id="@+id/im_arrow"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:src="@drawable/icon_vector" />
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
@ -24,6 +24,7 @@
|
||||
<color name="date_dialog_center_bg">#15787880</color>
|
||||
<color name="date_dialog_bg_unselected">#F2F2F7</color>
|
||||
<color name="view_div_color">#D9D9D9</color>
|
||||
<color name="bg_seekbar_video_play">#99F2F2F7</color>
|
||||
|
||||
|
||||
</resources>
|
||||
@ -36,12 +36,16 @@
|
||||
<string name="exit">Exit</string>
|
||||
<string name="allow">Allow</string>
|
||||
<string name="scan">Scanning…</string>
|
||||
<string name="text_photos">Photos</string>
|
||||
<string name="describe_photos">photos</string>
|
||||
<string name="describe_delete_photos">deleted photos</string>
|
||||
<string name="text_videos">Videos</string>
|
||||
<string name="describe_videos">videos</string>
|
||||
<string name="describe_delete_videos">deleted videos</string>
|
||||
<string name="text_audios">Audios</string>
|
||||
<string name="describe_audios">audios</string>
|
||||
<string name="describe_delete_audios">deleted audios</string>
|
||||
<string name="text_documents">Documents</string>
|
||||
<string name="describe_documents">documents</string>
|
||||
<string name="describe_delete_documents">deleted documents</string>
|
||||
<string name="finished">Finished!</string>
|
||||
@ -49,6 +53,7 @@
|
||||
<string name="exit_content">If you exit,the scanning results will be discarded.Are you sure you want to exit now?</string>
|
||||
<string name="date">Date</string>
|
||||
<string name="size">Size</string>
|
||||
<string name="duration">Duration</string>
|
||||
<string name="layout">Layout</string>
|
||||
<string name="hide_thumbnails">Hide thumbnails (%d)</string>
|
||||
<string name="hide_thumbnails_describe">Thumbnails refer to photos below 256 pixels</string>
|
||||
@ -64,6 +69,7 @@
|
||||
<string name="ok">OK</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="path">Path</string>
|
||||
<string name="type">Type</string>
|
||||
<string name="resolution">Resolution</string>
|
||||
<string name="recovering">Recovering...</string>
|
||||
<string name="recovering_content">It may take a few seconds to recover the file(s), please
|
||||
@ -78,6 +84,8 @@ wait..</string>
|
||||
<string name="confirm_delete_content">The file(s) will be completely deleted and cannot be recovered.</string>
|
||||
<string name="confirm_delete">Confirm delete?</string>
|
||||
<string name="view">View</string>
|
||||
<string name="not_found">Sorry!No %s found!</string>
|
||||
|
||||
|
||||
<string-array name="filter_date">
|
||||
<item>All</item>
|
||||
@ -86,12 +94,27 @@ wait..</string>
|
||||
<item>within 24 month</item>
|
||||
<item>Customize</item>
|
||||
</string-array>
|
||||
<string-array name="filter_size">
|
||||
<string-array name="filter_size_photo">
|
||||
<item>All</item>
|
||||
<item>0-1 M</item>
|
||||
<item>1-5 M</item>
|
||||
<item>>5 M</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="filter_documents_size">
|
||||
<item>All</item>
|
||||
<item>0-500 KB</item>
|
||||
<item>500 KB-1 M</item>
|
||||
<item>>1 M</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="filter_duration_video_audio">
|
||||
<item>All</item>
|
||||
<item>0-5 minutes</item>
|
||||
<item>5-20 minutes</item>
|
||||
<item>20-60 minutes</item>
|
||||
<item>>60 minutes</item>
|
||||
</string-array>
|
||||
<string-array name="filter_layout">
|
||||
<item>2 columns</item>
|
||||
<item>3 columns</item>
|
||||
|
||||