音频播放

This commit is contained in:
litingting 2025-10-23 18:19:17 +08:00
parent 063540eb58
commit 4fa3f505d0
12 changed files with 311 additions and 83 deletions

View File

@ -142,24 +142,19 @@ class PhotoDisplayDateChildAdapter(
item: ResultPhotosFiles,
viewType: Int
) {
when (holder) {
is TwoHolder -> holder.vb.run {
initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item, imageType)
}
is ThreeHolder -> holder.vb.run {
initDateView(rootLayout, imageSelect, textSize, imageThumbnail, item, imageType)
}
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)
@ -170,6 +165,9 @@ class PhotoDisplayDateChildAdapter(
addOrRemove(this, newStatus)
}
}
it.constraintLayout.setOnClickListener {
clickItem(this)
}
}
}

View File

@ -2,10 +2,16 @@ package com.ux.video.file.filerecovery.photo
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
@ -29,7 +35,9 @@ 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.video.PlayMediaManager
import com.ux.video.file.filerecovery.video.VideoPlayActivity
import java.io.File
class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
@ -39,7 +47,7 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
private var scanType: Int = VALUE_SCAN_TYPE_photo
private var myData: ResultPhotosFiles? = null
private lateinit var player: ExoPlayer
override fun inflateBinding(inflater: LayoutInflater): ActivityPhotoInfoBinding =
ActivityPhotoInfoBinding.inflate(inflater)
@ -65,37 +73,10 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
tvName.text = resultPhotosFiles.name
tvPath.text = resultPhotosFiles.path
tvSize.text = resultPhotosFiles.sizeString
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))))
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable?>,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable?>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
return false
}
})
.into(image)
layoutBottom.tvLeft.run {
text = resources.getString(R.string.delete)
setOnClickListener {
@ -109,7 +90,6 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
}
}
}
layoutBottom.tvRight.run {
text = resources.getString(R.string.recover)
setOnClickListener {
@ -134,12 +114,17 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
layoutPath.isVisible = true
layoutResolution.isVisible = true
layoutDate.isVisible = true
frameImage.setBackgroundResource(0)
layoutSeekbar.isVisible = false
layoutType.isVisible = false
layoutSize.isVisible = false
layoutDuration.isVisible = false
imPlay.isVisible = false
myData?.targetFile?.let { loadImage(image,it) }
}
VALUE_SCAN_TYPE_video, VALUE_SCAN_TYPE_deleted_video -> {
@ -148,12 +133,16 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
layoutResolution.isVisible = true
layoutDate.isVisible = true
layoutDuration.isVisible = true
frameImage.setBackgroundResource(0)
layoutSeekbar.isVisible = false
layoutType.isVisible = false
layoutSize.isVisible = false
imPlay.isVisible = true
myData?.let { data->
data.targetFile?.let { loadImage(image,it) }
frameImage.setOnClickListener {
startActivity(Intent(this@PhotoInfoActivity, VideoPlayActivity::class.java).apply {
putExtra(VideoPlayActivity.KEY_DATA, data)
@ -163,12 +152,25 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
}
VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> {
Common.showLog("----------音频")
layoutName.isVisible = true
layoutPath.isVisible = true
layoutSize.isVisible = true
layoutDate.isVisible = true
layoutDuration.isVisible = true
layoutSeekbar.isVisible = true
imPlay.isVisible = true
frameImage.setBackgroundResource(R.drawable.bg_info_music_f2f2f7_8)
image.setImageResource(R.drawable.image_info_music)
val params = image.layoutParams ?: ViewGroup.LayoutParams(
180.dpToPx(this@PhotoInfoActivity),
180.dpToPx(this@PhotoInfoActivity)
)
params.width = 180.dpToPx(this@PhotoInfoActivity)
params.height = 180.dpToPx(this@PhotoInfoActivity)
image.layoutParams = params
initPlayAudio()
layoutResolution.isVisible = false
layoutType.isVisible = false
}
@ -189,6 +191,49 @@ class PhotoInfoActivity : BaseActivity<ActivityPhotoInfoBinding>() {
}
private fun loadImage(image: ImageView,file: File){
Glide.with(this@PhotoInfoActivity)
.load(file)
.apply(RequestOptions().transform(CenterCrop(), RoundedCorners(8.dpToPx(this@PhotoInfoActivity))))
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable?>,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable?>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
return false
}
})
.into(image)
}
private fun initPlayAudio(){
myData?.targetFile?.let {
binding.run {
PlayMediaManager(context = this@PhotoInfoActivity, mediaFile = it,
seekBar = seekBar, playBtn = imPlay, onUpdateProgress = { current,total->
textTimeCurrent.text = current
textTimeTotal.text = total
} )
}
}
}
private fun complete(number: Int, type: Int) {
finish()
startActivity(Intent(this@PhotoInfoActivity, RecoverySuccessActivity::class.java).apply {

View File

@ -170,7 +170,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
this@PhotoSortingActivity,
PhotoInfoActivity::class.java
).apply {
putExtra(KEY_SCAN_TYPE,scanType)
putExtra(KEY_SCAN_TYPE, scanType)
putExtra(PhotoInfoActivity.KEY_CLICK_ITEM, item)
})
@ -189,7 +189,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
this@PhotoSortingActivity,
PhotoInfoActivity::class.java
).apply {
putExtra(KEY_SCAN_TYPE,scanType)
putExtra(KEY_SCAN_TYPE, scanType)
putExtra(PhotoInfoActivity.KEY_CLICK_ITEM, item)
})
}.apply {
@ -477,10 +477,20 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
private fun setSizeAdapter() {
binding.recyclerView.run {
val aPx = 16.dpToPx(context)
val bottom = 70.dpToPx(context)
when (scanType) {
VALUE_SCAN_TYPE_audio, VALUE_SCAN_TYPE_deleted_audio -> {
layoutManager = LinearLayoutManager(context)
setPadding(aPx, 0, 0, bottom)
}
else -> {
val bPx = 6.dpToPx(context)
setPadding(aPx, 0, bPx, 70.dpToPx(context))
setPadding(aPx, 0, bPx, bottom)
clipToPadding = false
layoutManager = GridLayoutManager(context, columns)
}
}
adapter = sizeSortAdapter
}
@ -685,6 +695,7 @@ class PhotoSortingActivity : BaseActivity<ActivityPhotoSortingBinding>() {
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)
}

View File

@ -0,0 +1,110 @@
package com.ux.video.file.filerecovery.video
import android.content.Context
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.widget.ImageView
import android.widget.SeekBar
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import com.ux.video.file.filerecovery.utils.Common
import java.io.File
class PlayMediaManager(var context: Context, var mediaFile: File, var playView: PlayerView? = null, var seekBar: SeekBar, var playBtn: ImageView, var onUpdateProgress:(currentStr: String, totalStr: String)-> Unit) {
private lateinit var player: ExoPlayer
private val updateHandler = Handler(Looper.getMainLooper())
init {
initPlayer()
playBtn.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?) {
}
})
}
private fun initPlayer() {
player = ExoPlayer.Builder(context).build()
playView?.player = player
val mediaItem = MediaItem.fromUri(Uri.fromFile(mediaFile))
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 -> {
playBtn.isSelected = false
// onPlayEnd()
}
}
}
})
player.setMediaItem(mediaItem)
player.prepare()
startProgressUpdater()
}
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()
onUpdateProgress(Common.formatDuration(pos),Common.formatDuration(dur))
seekBar.progress = progress
//
// binding.textTimeCurrent.text = Common.formatDuration(pos)
// binding.textTimeTotal.text = Common.formatDuration(dur)
}
updateHandler.postDelayed(this, 500)
}
})
}
}

View File

@ -53,44 +53,52 @@ class VideoPlayActivity : BaseActivity<ActivityVideoPlayBinding>() {
@Suppress("DEPRECATION")
intent.getParcelableExtra(KEY_DATA)
}
initPlayer()
// 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)
}
resultPhotosFiles.targetFile?.let {
PlayMediaManager(context = this@VideoPlayActivity, mediaFile = it, playView = playerView,
seekBar = seekBar, playBtn = playImage, onUpdateProgress = { current,total->
textTimeCurrent.text = current
textTimeTotal.text = total
} )
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
startProgressUpdater()
// 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 {

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="8dp"/>
<solid android:color="@color/date_dialog_bg_unselected"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -56,17 +56,57 @@
<ImageView
android:id="@+id/image"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="320dp" />
android:layout_height="match_parent" />
<ImageView
android:id="@+id/im_play"
android:layout_width="76dp"
android:layout_height="76dp"
android:layout_gravity="center"
android:src="@drawable/icon_info_play" />
android:src="@drawable/selector_play_button" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:id="@+id/layout_seekbar"
android:paddingHorizontal="10dp"
android:layout_gravity="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/main_sub_title"
android:textSize="10sp"
app:fontType="bold"
android: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="0"
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/main_sub_title"
android:textSize="10sp"
app:fontType="bold"
android:text="00:00" />
</LinearLayout>
</FrameLayout>

View File

@ -123,9 +123,8 @@
android:layout_marginStart="8dp"
android:src="@drawable/selector_arrow_up_down" />
</LinearLayout>
<ImageView
android:id="@+id/im_sort"
android:id="@+id/im_search"
android:layout_width="47dp"
android:layout_height="16dp"
android:layout_alignTop="@id/filter_date_layout"
@ -133,9 +132,17 @@
android:layout_alignParentEnd="true"
android:layout_marginEnd="8dp"
android:paddingHorizontal="16dp"
android:src="@drawable/icon_search" />
<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_toStartOf="@id/im_search"
android:paddingHorizontal="16dp"
android:src="@drawable/icon_sort" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -43,7 +43,7 @@
android:textColor="@color/white"
android:textSize="10sp"
app:fontType="bold"
tools:text="00:00" />
android:text="00:00" />
<SeekBar
android:id="@+id/seek_bar"
@ -51,7 +51,7 @@
android:layout_height="16dp"
android:layout_weight="1"
android:max="100"
android:progress="30"
android:progress="0"
android:progressDrawable="@drawable/seekbar_video_play"
android:splitTrack="false"
android:thumb="@drawable/seekbar_thumb" />
@ -64,7 +64,7 @@
android:textColor="@color/white"
android:textSize="10sp"
app:fontType="bold"
tools:text="00:00" />
android:text="00:00"/>
</LinearLayout>
<include

View File

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/constraint_layout"
android:layout_height="64dp">
<ImageView