This commit is contained in:
Binondi
2024-12-16 19:47:57 +05:30
parent 0fe7c4c25f
commit 24d50a3c01
5 changed files with 314 additions and 12 deletions

View File

@@ -4,7 +4,8 @@ import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2
import devs.org.calculator.adapters.ImagePreviewAdapter
import devs.org.calculator.callbacks.DialogActionsCallback
import devs.org.calculator.databinding.ActivityPreviewBinding
@@ -12,6 +13,7 @@ import devs.org.calculator.utils.DialogUtil
import devs.org.calculator.utils.FileManager
import kotlinx.coroutines.launch
import java.io.File
import devs.org.calculator.R
class PreviewActivity : AppCompatActivity() {
@@ -39,6 +41,14 @@ class PreviewActivity : AppCompatActivity() {
setupImagePreview()
clickListeners()
binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
}
})
}
private fun setupFileType() {
@@ -73,6 +83,25 @@ class PreviewActivity : AppCompatActivity() {
val fileName = FileManager.FileName(this).getFileNameFromUri(fileUri).toString()
}
override fun onPause() {
super.onPause()
if (filetype == FileManager.FileType.AUDIO) {
(binding.viewPager.adapter as? ImagePreviewAdapter)?.currentMediaPlayer?.pause()
}
}
override fun onDestroy() {
super.onDestroy()
if (filetype == FileManager.FileType.AUDIO) {
(binding.viewPager.adapter as? ImagePreviewAdapter)?.let { adapter ->
adapter.currentMediaPlayer?.release()
adapter.currentMediaPlayer = null
}
}
}
private fun clickListeners() {
binding.delete.setOnClickListener {
val fileUri = FileManager.FileManager().getContentUriImage(this, files[binding.viewPager.currentItem], filetype)
@@ -147,4 +176,6 @@ class PreviewActivity : AppCompatActivity() {
onBackPressed()
return true
}
}

View File

@@ -82,11 +82,42 @@ class FileAdapter(
}
itemView.setOnClickListener {
val intent = Intent(context, PreviewActivity::class.java).apply {
putExtra("type", fileTypes)
putExtra("position", position)
when(fileType){
FileManager.FileType.AUDIO -> {
// Create an intent to play audio using available audio players
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(FileManager.FileManager().getContentUriImage(context, file, fileType), "audio/*")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
try {
context.startActivity(intent)
} catch (e: Exception) {
Toast.makeText(context, "No audio player found!", Toast.LENGTH_SHORT).show()
}
}
FileManager.FileType.DOCUMENT -> {
// Create an intent to open the document using available viewers or file managers
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(FileManager.FileManager().getContentUriImage(context, file, fileType), "*/*")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
try {
context.startActivity(intent)
} catch (e: Exception) {
Toast.makeText(context, "No suitable app found to open this document!", Toast.LENGTH_SHORT).show()
}
}
else -> {
val intent = Intent(context, PreviewActivity::class.java).apply {
putExtra("type", fileTypes)
putExtra("position", position)
}
context.startActivity(intent)
}
}
context.startActivity(intent)
}
itemView.setOnLongClickListener {

View File

@@ -1,11 +1,15 @@
package devs.org.calculator.adapters
import android.content.Context
import android.media.MediaPlayer
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.MediaController
import android.widget.SeekBar
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
@@ -13,16 +17,20 @@ import devs.org.calculator.adapters.FileAdapter.FileDiffCallback
import devs.org.calculator.databinding.ViewpagerItemsBinding
import devs.org.calculator.utils.FileManager
import java.io.File
import devs.org.calculator.R
class ImagePreviewAdapter(
private val context: Context,
private var fileType: FileManager.FileType
) : RecyclerView.Adapter<ImagePreviewAdapter.ImageViewHolder>() {
// Use AsyncListDiffer for managing the list
private val differ = AsyncListDiffer(this, FileDiffCallback())
var currentMediaPlayer: MediaPlayer? = null
var isMediaPlayerPrepared = false
var currentViewHolder: ImageViewHolder? = null
private var currentPlayingPosition = -1
private var isPlaying = false
// Expose data management through differ
var images: List<File>
get() = differ.currentList
set(value) = differ.submitList(value)
@@ -35,15 +43,35 @@ class ImagePreviewAdapter(
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val imageUrl = images[position]
holder.bind(imageUrl)
currentViewHolder = holder
currentMediaPlayer?.let {
if (it.isPlaying) it.pause()
it.seekTo(0)
}
currentMediaPlayer = null
isMediaPlayerPrepared = false
if (currentMediaPlayer?.isPlaying == true) {
currentMediaPlayer?.stop()
currentMediaPlayer?.release()
}
currentMediaPlayer = null
}
override fun getItemCount(): Int = images.size
inner class ImageViewHolder(val binding: ViewpagerItemsBinding) : RecyclerView.ViewHolder(binding.root) {
inner class ImageViewHolder(private val binding: ViewpagerItemsBinding) : RecyclerView.ViewHolder(binding.root) {
private var mediaPlayer: MediaPlayer? = null
private var seekHandler = Handler(Looper.getMainLooper())
private var seekRunnable: Runnable? = null
fun bind(file: File) {
when (fileType) {
FileManager.FileType.VIDEO -> {
binding.imageView.visibility = View.GONE
binding.audioBg.visibility = View.GONE
binding.videoView.visibility = View.VISIBLE
val videoUri = Uri.fromFile(file)
@@ -73,19 +101,131 @@ class ImagePreviewAdapter(
FileManager.FileType.IMAGE -> {
binding.imageView.visibility = View.VISIBLE
binding.videoView.visibility = View.GONE
binding.audioBg.visibility = View.GONE
Glide.with(context)
.load(file)
.into(binding.imageView)
}
FileManager.FileType.AUDIO -> {
// Handle audio if necessary
binding.imageView.visibility = View.GONE
binding.audioBg.visibility = View.VISIBLE
binding.videoView.visibility = View.GONE
binding.audioTitle.text = file.name
setupAudioPlayer(file)
setupSeekBar()
setupPlaybackControls()
}
else -> {
// Handle other types if necessary
binding.imageView.visibility = View.VISIBLE
binding.audioBg.visibility = View.GONE
binding.videoView.visibility = View.GONE
}
}
}
private fun setupAudioPlayer(file: File) {
mediaPlayer = MediaPlayer().apply {
setDataSource(file.absolutePath)
setOnPreparedListener { mp ->
binding.audioSeekBar.max = mp.duration
isMediaPlayerPrepared = true
}
setOnCompletionListener {
// isPlaying = false
binding.playPause.setImageResource(R.drawable.play)
binding.audioSeekBar.progress = 0
seekHandler.removeCallbacks(seekRunnable!!)
}
prepareAsync()
}
}
private fun setupSeekBar() {
binding.audioSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser) {
mediaPlayer?.seekTo(progress)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
seekRunnable = Runnable {
mediaPlayer?.let { mp ->
if (mp.isPlaying) {
binding.audioSeekBar.progress = mp.currentPosition
seekHandler.postDelayed(seekRunnable!!, 100)
}
}
}
}
private fun setupPlaybackControls() {
binding.playPause.setOnClickListener {
if (isPlaying) {
pauseAudio()
} else {
playAudio()
}
}
binding.preview.setOnClickListener {
mediaPlayer?.let { mp ->
val newPosition = mp.currentPosition - 10000
mp.seekTo(maxOf(0, newPosition))
binding.audioSeekBar.progress = mp.currentPosition
}
}
binding.next.setOnClickListener {
mediaPlayer?.let { mp ->
val newPosition = mp.currentPosition + 10000
mp.seekTo(minOf(mp.duration, newPosition))
binding.audioSeekBar.progress = mp.currentPosition
}
}
}
private fun playAudio() {
mediaPlayer?.let { mp ->
if (currentPlayingPosition != -1 && currentPlayingPosition != adapterPosition) {
currentViewHolder?.pauseAudio()
}
mp.start()
isPlaying = true
binding.playPause.setImageResource(R.drawable.pause)
seekHandler.post(seekRunnable!!)
currentPlayingPosition = adapterPosition
currentViewHolder = this
}
}
private fun pauseAudio() {
mediaPlayer?.let { mp ->
if (mp.isPlaying) {
mp.pause()
isPlaying = false
binding.playPause.setImageResource(R.drawable.play)
seekHandler.removeCallbacks(seekRunnable!!)
}
}
}
fun releaseMediaPlayer() {
mediaPlayer?.let { mp ->
if (mp.isPlaying) {
mp.stop()
}
mp.release()
mediaPlayer = null
isPlaying = false
seekHandler.removeCallbacks(seekRunnable!!)
}
}
private fun playVideoAtPosition(position: Int) {
val nextFile = images[position]
if (fileType == FileManager.FileType.VIDEO) {
@@ -95,5 +235,10 @@ class ImagePreviewAdapter(
}
}
}
override fun onViewRecycled(holder: ImageViewHolder) {
super.onViewRecycled(holder)
holder.releaseMediaPlayer()
}
}

View File

@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView
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="match_parent"
android:layout_gravity="center"
android:layout_margin="4dp"
app:cardCornerRadius="8dp">
@@ -15,6 +17,7 @@
app:zoomage_animateOnReset="true"
app:zoomage_autoResetMode="UNDER"
app:zoomage_autoCenter="true"
android:visibility="gone"
app:zoomage_zoomable="true"
app:zoomage_translatable="true"
app:zoomage_minScale="0.6"
@@ -24,6 +27,99 @@
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:id="@+id/videoView"/>
<com.google.android.material.card.MaterialCardView
android:id="@+id/audioBg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="20dp"
style="@style/Widget.Material3.CardView.Outlined">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="5dp"
android:src="@drawable/music"
android:padding="3dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="audio.mp3"
android:layout_margin="5dp"
android:id="@+id/audioTitle"/>
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:id="@+id/audioSeekBar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<com.google.android.material.card.MaterialCardView
android:layout_width="40dp"
android:layout_height="40dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/previous"
android:padding="3dp"
android:id="@+id/preview"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="40dp"
android:layout_margin="8dp"
android:layout_height="40dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/play"
android:padding="3dp"
android:id="@+id/playPause"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="40dp"
android:layout_height="40dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:padding="3dp"
android:src="@drawable/next"
android:id="@+id/next"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.card.MaterialCardView>

View File

@@ -5,7 +5,6 @@
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
<item name="colorOnPrimary">@color/black</item>
<item name="android:background">@color/black</item>
<!-- Secondary brand color -->
<item name="colorSecondary">@color/colorSecondary</item>
<item name="colorSecondaryVariant">@color/colorSecondary</item>