✨
This commit is contained in:
@@ -59,6 +59,19 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".activities.PreviewActivity"
|
android:name=".activities.PreviewActivity"
|
||||||
android:configChanges="orientation|screenSize"/>
|
android:configChanges="orientation|screenSize"/>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="devs.org.calculator.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -73,7 +73,7 @@ class PreviewActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun clickListeners() {
|
private fun clickListeners() {
|
||||||
binding.delete.setOnClickListener {
|
binding.delete.setOnClickListener {
|
||||||
val fileUri = FileManager.FileManager().getContentUri(this, files[binding.viewPager.currentItem], filetype)
|
val fileUri = FileManager.FileManager().getContentUriImage(this, files[binding.viewPager.currentItem], filetype)
|
||||||
if (fileUri != null) {
|
if (fileUri != null) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle("Delete File")
|
.setTitle("Delete File")
|
||||||
@@ -93,7 +93,7 @@ class PreviewActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.unHide.setOnClickListener {
|
binding.unHide.setOnClickListener {
|
||||||
val fileUri = FileManager.FileManager().getContentUri(this, files[binding.viewPager.currentItem], filetype)
|
val fileUri = FileManager.FileManager().getContentUriImage(this, files[binding.viewPager.currentItem], filetype)
|
||||||
if (fileUri != null) {
|
if (fileUri != null) {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle("Unhide File")
|
.setTitle("Unhide File")
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package devs.org.calculator.adapters
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -16,19 +15,21 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import devs.org.calculator.R
|
import devs.org.calculator.R
|
||||||
import devs.org.calculator.activities.BaseGalleryActivity
|
|
||||||
import devs.org.calculator.activities.PreviewActivity
|
import devs.org.calculator.activities.PreviewActivity
|
||||||
import devs.org.calculator.utils.DialogUtil
|
|
||||||
import devs.org.calculator.utils.FileManager
|
import devs.org.calculator.utils.FileManager
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.collections.remove
|
|
||||||
|
|
||||||
class FileAdapter(private val fileType: FileManager.FileType, var context: Context, private var lifecycleOwner: LifecycleOwner) :
|
class FileAdapter(
|
||||||
|
private val fileType: FileManager.FileType,
|
||||||
|
var context: Context,
|
||||||
|
private var lifecycleOwner: LifecycleOwner
|
||||||
|
) :
|
||||||
ListAdapter<File, FileAdapter.FileViewHolder>(FileDiffCallback()) {
|
ListAdapter<File, FileAdapter.FileViewHolder>(FileDiffCallback()) {
|
||||||
|
|
||||||
private val selectedItems = mutableSetOf<Int>()
|
private val selectedItems = mutableSetOf<Int>()
|
||||||
private var isSelectionMode = false
|
private var isSelectionMode = false
|
||||||
|
private var fileName = "Unknown File"
|
||||||
|
|
||||||
inner class FileViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class FileViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
private val imageView: ImageView = view.findViewById(R.id.imageView)
|
private val imageView: ImageView = view.findViewById(R.id.imageView)
|
||||||
@@ -42,6 +43,7 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
|
|||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileManager.FileType.VIDEO -> {
|
FileManager.FileType.VIDEO -> {
|
||||||
Glide.with(imageView)
|
Glide.with(imageView)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
@@ -49,6 +51,7 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
|
|||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val resourceId = when (fileType) {
|
val resourceId = when (fileType) {
|
||||||
FileManager.FileType.AUDIO -> R.drawable.ic_audio
|
FileManager.FileType.AUDIO -> R.drawable.ic_audio
|
||||||
@@ -61,17 +64,20 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
|
|||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
|
|
||||||
|
|
||||||
var fileTypes = when(fileType){
|
var fileTypes = when (fileType) {
|
||||||
|
|
||||||
FileManager.FileType.IMAGE -> {
|
FileManager.FileType.IMAGE -> {
|
||||||
"IMAGE"
|
"IMAGE"
|
||||||
}
|
}
|
||||||
|
|
||||||
FileManager.FileType.VIDEO -> {
|
FileManager.FileType.VIDEO -> {
|
||||||
"VIDEO"
|
"VIDEO"
|
||||||
}
|
}
|
||||||
|
|
||||||
FileManager.FileType.AUDIO -> {
|
FileManager.FileType.AUDIO -> {
|
||||||
"AUDIO"
|
"AUDIO"
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> "DOCUMENT"
|
else -> "DOCUMENT"
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -83,20 +89,27 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
|
|||||||
|
|
||||||
}
|
}
|
||||||
itemView.setOnLongClickListener {
|
itemView.setOnLongClickListener {
|
||||||
val fileUri = FileManager.FileManager().getContentUri(context, file, fileType)
|
|
||||||
if (fileUri == null) {
|
|
||||||
Toast.makeText(context, "Unable to access file: $file", Toast.LENGTH_SHORT).show()
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
|
|
||||||
val fileName = FileManager.FileName(context).getFileNameFromUri(fileUri)?.toString() ?: "Unknown File"
|
val fileUri = FileManager.FileManager().getContentUriImage(context, file, fileType)
|
||||||
|
if (fileUri == null) {
|
||||||
|
Toast.makeText(context, "Unable to access file: $file", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
|
||||||
|
return@setOnLongClickListener true
|
||||||
|
|
||||||
|
}
|
||||||
|
fileName = FileManager.FileName(context).getFileNameFromUri(fileUri)?.toString()
|
||||||
|
?: "Unknown File"
|
||||||
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder(context)
|
MaterialAlertDialogBuilder(context)
|
||||||
.setTitle("Details")
|
.setTitle("Details")
|
||||||
.setMessage("File Name: $fileName\n\nYou can delete or unhide this file.")
|
.setMessage("File Name: $fileName\n\nFile Path: $file\n\nYou can delete or unhide this file.")
|
||||||
.setPositiveButton("Delete") { dialog, _ ->
|
.setPositiveButton("Delete") { dialog, _ ->
|
||||||
lifecycleOwner.lifecycleScope.launch {
|
lifecycleOwner.lifecycleScope.launch {
|
||||||
FileManager(context, lifecycleOwner).deletePhotoFromExternalStorage(fileUri)
|
FileManager(context, lifecycleOwner).deletePhotoFromExternalStorage(
|
||||||
|
fileUri
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val currentList = currentList.toMutableList()
|
val currentList = currentList.toMutableList()
|
||||||
currentList.remove(file)
|
currentList.remove(file)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
|
||||||
class FileManager(private val context: Context, private val lifecycleOwner: LifecycleOwner) {
|
class FileManager(private val context: Context, private val lifecycleOwner: LifecycleOwner) {
|
||||||
private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest>
|
private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest>
|
||||||
@@ -224,69 +225,29 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
|
|||||||
|
|
||||||
}
|
}
|
||||||
class FileManager(){
|
class FileManager(){
|
||||||
fun getContentUri(context: Context, file: File, fileType: FileType): Uri? {
|
fun getContentUriImage(context: Context, file: File, fileType: FileType): Uri? {
|
||||||
when(fileType){
|
|
||||||
FileType.IMAGE -> {
|
|
||||||
val projection = arrayOf(MediaStore.MediaColumns._ID)
|
|
||||||
val selection = "${MediaStore.MediaColumns.DATA} = ?"
|
|
||||||
val selectionArgs = arrayOf(file.absolutePath)
|
|
||||||
val queryUri = MediaStore.Files.getContentUri("external")
|
|
||||||
|
|
||||||
context.contentResolver.query(queryUri, projection, selection, selectionArgs, null)?.use { cursor ->
|
// Query MediaStore for the file
|
||||||
if (cursor.moveToFirst()) {
|
val projection = arrayOf(MediaStore.MediaColumns._ID)
|
||||||
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
|
val selection = "${MediaStore.MediaColumns.DATA} = ?"
|
||||||
return Uri.withAppendedPath(queryUri, id.toString())
|
val selectionArgs = arrayOf(file.absolutePath)
|
||||||
}
|
val queryUri = MediaStore.Files.getContentUri("external")
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
FileType.VIDEO -> {
|
context.contentResolver.query(queryUri, projection, selection, selectionArgs, null)?.use { cursor ->
|
||||||
val projection = arrayOf(MediaStore.Video.Media._ID)
|
if (cursor.moveToFirst()) {
|
||||||
val selection = "${MediaStore.Video.Media.DATA} = ?"
|
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
|
||||||
val selectionArgs = arrayOf(file.absolutePath)
|
return Uri.withAppendedPath(queryUri, id.toString())
|
||||||
val queryUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
|
||||||
|
|
||||||
context.contentResolver.query(queryUri, projection, selection, selectionArgs, null)?.use { cursor ->
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID))
|
|
||||||
return Uri.withAppendedPath(queryUri, id.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
FileType.AUDIO -> {
|
|
||||||
val projection = arrayOf(MediaStore.Audio.Media._ID)
|
|
||||||
val selection = "${MediaStore.Audio.Media.DATA} = ?"
|
|
||||||
val selectionArgs = arrayOf(file.absolutePath)
|
|
||||||
val queryUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
|
||||||
|
|
||||||
context.contentResolver.query(queryUri, projection, selection, selectionArgs, null)?.use { cursor ->
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID))
|
|
||||||
return Uri.withAppendedPath(queryUri, id.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
FileType.DOCUMENT -> {
|
|
||||||
val projection = arrayOf(MediaStore.Files.FileColumns._ID)
|
|
||||||
val selection = "${MediaStore.Files.FileColumns.DATA} = ?"
|
|
||||||
val selectionArgs = arrayOf(file.absolutePath)
|
|
||||||
val queryUri = MediaStore.Files.getContentUri("external")
|
|
||||||
|
|
||||||
context.contentResolver.query(queryUri, projection, selection, selectionArgs, null)?.use { cursor ->
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID))
|
|
||||||
return Uri.withAppendedPath(queryUri, id.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the file is not found in MediaStore, fallback to FileProvider for hidden files
|
||||||
|
return if (file.exists()) {
|
||||||
|
FileProvider.getUriForFile(context, "devs.org.calculator.fileprovider", file)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
8
app/src/main/res/xml/file_paths.xml
Normal file
8
app/src/main/res/xml/file_paths.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- Allow access to external files -->
|
||||||
|
<external-path name="external_files" path="." />
|
||||||
|
<!-- Allow access to hidden directories -->
|
||||||
|
<external-files-path name="hidden_files" path=".CalculatorHide/" />
|
||||||
|
</paths>
|
||||||
|
|
||||||
Reference in New Issue
Block a user