Changes For Folder Feature
This commit is contained in:
1
app/src/main/assets/hiding_files.json
Normal file
1
app/src/main/assets/hiding_files.json
Normal file
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
package devs.org.calculator.activities
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
@@ -9,29 +9,33 @@ import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import devs.org.calculator.R
|
||||
import devs.org.calculator.adapters.FileAdapter
|
||||
import devs.org.calculator.adapters.FolderAdapter
|
||||
import devs.org.calculator.callbacks.DialogActionsCallback
|
||||
import devs.org.calculator.callbacks.FileProcessCallback
|
||||
import devs.org.calculator.databinding.ActivityHiddenBinding
|
||||
import devs.org.calculator.databinding.ProccessingDialogBinding
|
||||
import devs.org.calculator.utils.DialogUtil
|
||||
import devs.org.calculator.utils.FileManager
|
||||
import devs.org.calculator.utils.FileManager.Companion.HIDDEN_DIR
|
||||
import devs.org.calculator.utils.FolderManager
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class HiddenActivity : AppCompatActivity() {
|
||||
|
||||
@@ -45,19 +49,49 @@ class HiddenActivity : AppCompatActivity() {
|
||||
private val fileManager = FileManager(this, this)
|
||||
private val folderManager = FolderManager(this)
|
||||
private val dialogUtil = DialogUtil(this)
|
||||
|
||||
private var customDialog: androidx.appcompat.app.AlertDialog? = null
|
||||
private val STORAGE_PERMISSION_CODE = 101
|
||||
private val PICK_FILE_REQUEST_CODE = 102
|
||||
private var currentFolder: File? = null
|
||||
private var folderAdapter: FolderAdapter? = null
|
||||
val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
||||
|
||||
private lateinit var pickImageLauncher: ActivityResultLauncher<Intent>
|
||||
private var dialogShowTime: Long = 0
|
||||
private val MINIMUM_DIALOG_DURATION = 1700L
|
||||
|
||||
private fun showCustomDialog(i: Int) {
|
||||
val dialogView = ProccessingDialogBinding.inflate(layoutInflater)
|
||||
customDialog = MaterialAlertDialogBuilder(this)
|
||||
.setView(dialogView.root)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
dialogView.title.text = "Hiding $i files"
|
||||
customDialog?.show()
|
||||
dialogShowTime = System.currentTimeMillis()
|
||||
|
||||
}
|
||||
|
||||
private fun dismissCustomDialog() {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val elapsedTime = currentTime - dialogShowTime
|
||||
|
||||
if (elapsedTime < MINIMUM_DIALOG_DURATION) {
|
||||
val remainingTime = MINIMUM_DIALOG_DURATION - elapsedTime
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
customDialog?.dismiss()
|
||||
customDialog = null
|
||||
}, remainingTime)
|
||||
} else {
|
||||
customDialog?.dismiss()
|
||||
customDialog = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
binding = ActivityHiddenBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
//initialized animations for fabs
|
||||
fabOpen = AnimationUtils.loadAnimation(this, R.anim.fab_open)
|
||||
fabClose = AnimationUtils.loadAnimation(this, R.anim.fab_close)
|
||||
@@ -70,6 +104,7 @@ class HiddenActivity : AppCompatActivity() {
|
||||
binding.addAudio.visibility = View.GONE
|
||||
binding.addDocument.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
binding.deleteSelected.visibility = View.GONE
|
||||
|
||||
binding.fabExpend.setOnClickListener {
|
||||
if (isFabOpen) {
|
||||
@@ -84,6 +119,13 @@ class HiddenActivity : AppCompatActivity() {
|
||||
binding.addImage.setOnClickListener { openFilePicker("image/*") }
|
||||
binding.addVideo.setOnClickListener { openFilePicker("video/*") }
|
||||
binding.addAudio.setOnClickListener { openFilePicker("audio/*") }
|
||||
binding.back.setOnClickListener {
|
||||
if (currentFolder != null) {
|
||||
pressBack()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
binding.addDocument.setOnClickListener { openFilePicker("*/*") }
|
||||
binding.addFolder.setOnClickListener {
|
||||
dialogUtil.createInputDialog(
|
||||
@@ -101,50 +143,104 @@ class HiddenActivity : AppCompatActivity() {
|
||||
|
||||
fileManager.askPermission(this)
|
||||
listFoldersInHiddenDirectory()
|
||||
|
||||
setupDeleteButton()
|
||||
|
||||
pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val clipData = result.data?.clipData
|
||||
val uriList = mutableListOf<Uri>()
|
||||
|
||||
if (clipData != null) {
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
val uri = clipData.getItemAt(i).uri
|
||||
uriList.add(uri)
|
||||
}
|
||||
} else {
|
||||
result.data?.data?.let { uriList.add(it) }
|
||||
}
|
||||
|
||||
if (uriList.isNotEmpty()) {
|
||||
showCustomDialog(uriList.size)
|
||||
lifecycleScope.launch {
|
||||
if (currentFolder != null){
|
||||
FileManager(this@HiddenActivity, this@HiddenActivity)
|
||||
.processMultipleFiles(uriList, currentFolder!!,
|
||||
object : FileProcessCallback {
|
||||
override fun onFilesProcessedSuccessfully(copiedFiles: List<File>) {
|
||||
Toast.makeText(this@HiddenActivity, "${copiedFiles.size} ${getString(R.string.documents_hidden_successfully)}", Toast.LENGTH_SHORT).show()
|
||||
openFolder(currentFolder!!)
|
||||
dismissCustomDialog()
|
||||
}
|
||||
|
||||
override fun onFileProcessFailed() {
|
||||
Toast.makeText(this@HiddenActivity,
|
||||
getString(R.string.failed_to_hide_files), Toast.LENGTH_SHORT).show()
|
||||
dismissCustomDialog()
|
||||
}
|
||||
|
||||
})
|
||||
}else{
|
||||
Toast.makeText(
|
||||
this@HiddenActivity,
|
||||
getString(R.string.there_was_a_problem_in_the_folder),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
dismissCustomDialog()
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.no_files_selected), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
askPermissiom()
|
||||
}
|
||||
|
||||
private fun askPermissiom() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
|
||||
if (!Environment.isExternalStorageManager()){
|
||||
val intent = Intent().setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkAndRequestStoragePermission()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAndRequestStoragePermission() {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) != PackageManager.PERMISSION_GRANTED ||
|
||||
ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
),
|
||||
STORAGE_PERMISSION_CODE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFilePicker(mimeType: String) {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
type = mimeType
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
}
|
||||
startActivityForResult(intent, PICK_FILE_REQUEST_CODE)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == STORAGE_PERMISSION_CODE) {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d("HiddenActivity", "READ/WRITE_EXTERNAL_STORAGE permission granted via onRequestPermissionsResult")
|
||||
listFoldersInHiddenDirectory()
|
||||
} else {
|
||||
Log.d("HiddenActivity", "READ/WRITE_EXTERNAL_STORAGE permission denied via onRequestPermissionsResult")
|
||||
// Handle denied case, maybe show a message or disable functionality
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("This method has been deprecated in favor of using the Activity Result API\n which brings increased type safety via an {@link ActivityResultContract} and the prebuilt\n contracts for common intents available in\n {@link androidx.activity.result.contract.ActivityResultContracts}, provides hooks for\n testing, and allow receiving results in separate, testable classes independent from your\n activity. Use\n {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}\n with the appropriate {@link ActivityResultContract} and handling the result in the\n {@link ActivityResultCallback#onActivityResult(Object) callback}.")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == STORAGE_PERMISSION_CODE) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
if (Environment.isExternalStorageManager()) {
|
||||
listFoldersInHiddenDirectory()
|
||||
} else {
|
||||
// Handle denied case
|
||||
}
|
||||
}
|
||||
} else if (requestCode == PICK_FILE_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||
data?.data?.let { uri ->
|
||||
Log.d("HiddenActivity", "Selected file URI: $uri")
|
||||
copyFileToHiddenDirectory(uri)
|
||||
}
|
||||
}
|
||||
pickImageLauncher.launch(intent)
|
||||
}
|
||||
|
||||
private fun listFoldersInHiddenDirectory() {
|
||||
@@ -163,7 +259,16 @@ class HiddenActivity : AppCompatActivity() {
|
||||
openFolder(clickedFolder)
|
||||
},
|
||||
onFolderLongClick = { folder ->
|
||||
// go to selection mode
|
||||
// Enter selection mode
|
||||
binding.fabExpend.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.GONE
|
||||
binding.deleteSelected.visibility = View.VISIBLE
|
||||
},
|
||||
onSelectionModeChanged = { isSelectionMode ->
|
||||
if (!isSelectionMode) {
|
||||
binding.deleteSelected.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
)
|
||||
binding.recyclerView.adapter = folderAdapter
|
||||
@@ -191,6 +296,7 @@ class HiddenActivity : AppCompatActivity() {
|
||||
// Read files in the clicked folder and update RecyclerView
|
||||
val files = folderManager.getFilesInFolder(folder)
|
||||
Log.d("HiddenActivity", "Found ${files.size} files in ${folder.name}")
|
||||
binding.folderName.text = folder.name
|
||||
|
||||
if (files.isNotEmpty()) {
|
||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
|
||||
@@ -253,7 +359,7 @@ class HiddenActivity : AppCompatActivity() {
|
||||
binding.addVideo.visibility = View.VISIBLE
|
||||
binding.addAudio.visibility = View.VISIBLE
|
||||
binding.addDocument.visibility = View.VISIBLE
|
||||
binding.addFolder.visibility = View.VISIBLE // Keep this visible if in folder list, but should be GONE when showing files
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
|
||||
isFabOpen = true
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
@@ -279,31 +385,6 @@ class HiddenActivity : AppCompatActivity() {
|
||||
binding.fabExpend.setImageResource(R.drawable.ic_add)
|
||||
}
|
||||
|
||||
private fun copyFileToHiddenDirectory(uri: Uri) {
|
||||
currentFolder?.let { destinationFolder ->
|
||||
try {
|
||||
val inputStream: InputStream? = contentResolver.openInputStream(uri)
|
||||
val fileName = getFileNameFromUri(uri) ?: "unknown_file"
|
||||
val destinationFile = File(destinationFolder, fileName)
|
||||
|
||||
inputStream?.use { input ->
|
||||
val outputStream: OutputStream = FileOutputStream(destinationFile)
|
||||
outputStream.use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
Log.d("HiddenActivity", "File copied to: ${destinationFile.absolutePath}")
|
||||
// Refresh the file list in the RecyclerView
|
||||
currentFolder?.let { openFolder(it) }
|
||||
} catch (e: Exception) {
|
||||
Log.e("HiddenActivity", "Error copying file", e)
|
||||
// TODO: Show error message to user
|
||||
}
|
||||
} ?: run {
|
||||
Log.e("HiddenActivity", "Current folder is null, cannot copy file")
|
||||
// TODO: Show error message to user
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFileNameFromUri(uri: Uri): String? {
|
||||
var name: String? = null
|
||||
@@ -318,102 +399,70 @@ class HiddenActivity : AppCompatActivity() {
|
||||
return name
|
||||
}
|
||||
|
||||
private fun showFileOptionsDialog(file: File) {
|
||||
val options = arrayOf("Delete", "Rename", "Share")
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Choose an action for ${file.name}")
|
||||
.setItems(options) { dialog, which ->
|
||||
when (which) {
|
||||
0 -> deleteFile(file)
|
||||
1 -> renameFile(file)
|
||||
2 -> shareFile(file)
|
||||
}
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun deleteFile(file: File) {
|
||||
Log.d("HiddenActivity", "Deleting file: ${file.name}")
|
||||
if (file.exists()) {
|
||||
if (file.delete()) {
|
||||
Log.d("HiddenActivity", "File deleted successfully")
|
||||
// Refresh the file list in the RecyclerView
|
||||
currentFolder?.let { openFolder(it) }
|
||||
} else {
|
||||
Log.e("HiddenActivity", "Failed to delete file: ${file.absolutePath}")
|
||||
// TODO: Show error message to user
|
||||
}
|
||||
} else {
|
||||
Log.e("HiddenActivity", "File not found for deletion: ${file.absolutePath}")
|
||||
// TODO: Show error message to user
|
||||
}
|
||||
}
|
||||
|
||||
private fun renameFile(file: File) {
|
||||
Log.d("HiddenActivity", "Renaming file: ${file.name}")
|
||||
val inputEditText = EditText(this)
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Rename ${file.name}")
|
||||
.setView(inputEditText)
|
||||
.setPositiveButton("Rename") { dialog, _ ->
|
||||
val newName = inputEditText.text.toString().trim()
|
||||
if (newName.isNotEmpty()) {
|
||||
val parentDir = file.parentFile
|
||||
if (parentDir != null) {
|
||||
val newFile = File(parentDir, newName)
|
||||
if (file.renameTo(newFile)) {
|
||||
Log.d("HiddenActivity", "File renamed to: ${newFile.name}")
|
||||
currentFolder?.let { openFolder(it) }
|
||||
} else {
|
||||
Log.e("HiddenActivity", "Failed to rename file: ${file.absolutePath} to ${newFile.absolutePath}")
|
||||
private fun setupDeleteButton() {
|
||||
binding.deleteSelected.setOnClickListener {
|
||||
val selectedFolders = folderAdapter?.getSelectedItems() ?: emptyList()
|
||||
if (selectedFolders.isNotEmpty()) {
|
||||
dialogUtil.showMaterialDialog(
|
||||
getString(R.string.delete_items),
|
||||
getString(R.string.are_you_sure_you_want_to_delete_selected_items),
|
||||
getString(R.string.delete),
|
||||
getString(R.string.cancel),
|
||||
object : DialogUtil.DialogCallback {
|
||||
override fun onPositiveButtonClicked() {
|
||||
var allDeleted = true
|
||||
selectedFolders.forEach { folder ->
|
||||
if (!folderManager.deleteFolder(folder)) {
|
||||
allDeleted = false
|
||||
}
|
||||
}
|
||||
if (allDeleted) {
|
||||
Toast.makeText(this@HiddenActivity, getString(R.string.folder_deleted_successfully), Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(this@HiddenActivity, getString(R.string.some_items_could_not_be_deleted), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
folderAdapter?.clearSelection()
|
||||
binding.deleteSelected.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
listFoldersInHiddenDirectory()
|
||||
}
|
||||
} else {
|
||||
Log.e("HiddenActivity", "Parent directory is null for renaming: ${file.absolutePath}")
|
||||
}
|
||||
} else {
|
||||
Log.d("HiddenActivity", "New file name is empty")
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun shareFile(file: File) {
|
||||
val uri: Uri? = FileProvider.getUriForFile(this, "${packageName}.fileprovider", file)
|
||||
uri?.let { fileUri ->
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = contentResolver.getType(fileUri) ?: "*/*"
|
||||
putExtra(Intent.EXTRA_STREAM, fileUri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
override fun onNegativeButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun onNaturalButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
startActivity(Intent.createChooser(shareIntent, "Share ${file.name}"))
|
||||
} ?: run {
|
||||
Log.e("HiddenActivity", "Could not get URI for sharing file: ${file.absolutePath}")
|
||||
//Show error message to user
|
||||
}
|
||||
}
|
||||
|
||||
private fun pressBack(){
|
||||
currentFolder = null
|
||||
if (isFabOpen) {
|
||||
closeFabs()
|
||||
}
|
||||
if (folderAdapter != null) {
|
||||
binding.recyclerView.adapter = folderAdapter
|
||||
}
|
||||
binding.folderName.text = getString(R.string.hidden_space)
|
||||
listFoldersInHiddenDirectory()
|
||||
binding.fabExpend.visibility = View.GONE
|
||||
binding.addImage.visibility = View.GONE
|
||||
binding.addVideo.visibility = View.GONE
|
||||
binding.addAudio.visibility = View.GONE
|
||||
binding.addDocument.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@Deprecated("This method has been deprecated in favor of using the\n {@link OnBackPressedDispatcher} via {@link #getOnBackPressedDispatcher()}.\n The OnBackPressedDispatcher controls how back button events are dispatched\n to one or more {@link OnBackPressedCallback} objects.")
|
||||
override fun onBackPressed() {
|
||||
if (currentFolder != null) {
|
||||
currentFolder = null
|
||||
if (isFabOpen) {
|
||||
closeFabs()
|
||||
}
|
||||
if (folderAdapter != null) {
|
||||
binding.recyclerView.adapter = folderAdapter
|
||||
}
|
||||
listFoldersInHiddenDirectory()
|
||||
binding.fabExpend.visibility = View.GONE
|
||||
binding.addImage.visibility = View.GONE
|
||||
binding.addVideo.visibility = View.GONE
|
||||
binding.addAudio.visibility = View.GONE
|
||||
binding.addDocument.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
pressBack()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import devs.org.calculator.R
|
||||
import devs.org.calculator.activities.PreviewActivity
|
||||
import devs.org.calculator.utils.FileManager
|
||||
@@ -215,18 +216,20 @@ class FileAdapter(
|
||||
|
||||
private fun showFileOptionsDialog(file: File) {
|
||||
val options = arrayOf(
|
||||
context.getString(R.string.delete),
|
||||
context.getString(R.string.un_hide),
|
||||
context.getString(R.string.rename),
|
||||
context.getString(R.string.delete),
|
||||
context.getString(R.string.share)
|
||||
)
|
||||
|
||||
AlertDialog.Builder(context)
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(context.getString(R.string.file_options))
|
||||
.setItems(options) { dialog, which ->
|
||||
when (which) {
|
||||
0 -> deleteFile(file)
|
||||
0 -> unHideFile(file)
|
||||
1 -> renameFile(file)
|
||||
2 -> shareFile(file)
|
||||
2 -> deleteFile(file)
|
||||
3 -> shareFile(file)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
@@ -234,6 +237,20 @@ class FileAdapter(
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun unHideFile(file: File) {
|
||||
FileManager(context, lifecycleOwner).unHideFile(
|
||||
file = file,
|
||||
onSuccess = {
|
||||
fileOperationCallback?.onFileDeleted(file)
|
||||
|
||||
},
|
||||
onError = { errorMessage ->
|
||||
|
||||
Toast.makeText(context, "Failed to unhide: $errorMessage", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun deleteFile(file: File) {
|
||||
if (file.delete()) {
|
||||
fileOperationCallback?.onFileDeleted(file)
|
||||
@@ -249,7 +266,7 @@ class FileAdapter(
|
||||
selectAll()
|
||||
}
|
||||
|
||||
AlertDialog.Builder(context)
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(context.getString(R.string.rename_file))
|
||||
.setView(inputEditText)
|
||||
.setPositiveButton(context.getString(R.string.rename)) { dialog, _ ->
|
||||
|
||||
@@ -3,6 +3,7 @@ package devs.org.calculator.adapters
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
@@ -12,21 +13,55 @@ import java.io.File
|
||||
|
||||
class FolderAdapter(
|
||||
private val onFolderClick: (File) -> Unit,
|
||||
private val onFolderLongClick: (File) -> Unit
|
||||
private val onFolderLongClick: (File) -> Unit,
|
||||
private val onSelectionModeChanged: (Boolean) -> Unit
|
||||
) : ListAdapter<File, FolderAdapter.FolderViewHolder>(FolderDiffCallback()) {
|
||||
|
||||
class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val folderNameTextView: TextView = itemView.findViewById(R.id.folderName)
|
||||
private val selectedItems = mutableSetOf<Int>()
|
||||
private var isSelectionMode = false
|
||||
|
||||
fun bind(folder: File, onFolderClick: (File) -> Unit, onFolderLongClick: (File) -> Unit) {
|
||||
inner class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val folderNameTextView: TextView = itemView.findViewById(R.id.folderName)
|
||||
val selectedView: ImageView = itemView.findViewById(R.id.selected)
|
||||
val selectedLayer: View = itemView.findViewById(R.id.selectedLayer)
|
||||
|
||||
fun bind(folder: File, onFolderClick: (File) -> Unit, onFolderLongClick: (File) -> Unit, isSelected: Boolean) {
|
||||
folderNameTextView.text = folder.name
|
||||
|
||||
itemView.setOnClickListener { onFolderClick(folder) }
|
||||
selectedView.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
selectedLayer.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
|
||||
itemView.setOnClickListener {
|
||||
if (isSelectionMode) {
|
||||
toggleSelection(adapterPosition)
|
||||
} else {
|
||||
onFolderClick(folder)
|
||||
}
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
onFolderLongClick(folder)
|
||||
if (!isSelectionMode) {
|
||||
isSelectionMode = true
|
||||
onSelectionModeChanged(true)
|
||||
onFolderLongClick(folder)
|
||||
toggleSelection(adapterPosition)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleSelection(position: Int) {
|
||||
if (selectedItems.contains(position)) {
|
||||
selectedItems.remove(position)
|
||||
if (selectedItems.isEmpty()) {
|
||||
isSelectionMode = false
|
||||
onSelectionModeChanged(false)
|
||||
}
|
||||
} else {
|
||||
selectedItems.add(position)
|
||||
}
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FolderViewHolder {
|
||||
@@ -36,7 +71,20 @@ class FolderAdapter(
|
||||
|
||||
override fun onBindViewHolder(holder: FolderViewHolder, position: Int) {
|
||||
val folder = getItem(position)
|
||||
holder.bind(folder, onFolderClick, onFolderLongClick)
|
||||
holder.bind(folder, onFolderClick, onFolderLongClick, selectedItems.contains(position))
|
||||
}
|
||||
|
||||
fun getSelectedItems(): List<File> {
|
||||
return selectedItems.mapNotNull { position ->
|
||||
if (position < itemCount) getItem(position) else null
|
||||
}
|
||||
}
|
||||
|
||||
fun clearSelection() {
|
||||
selectedItems.clear()
|
||||
isSelectionMode = false
|
||||
onSelectionModeChanged(false)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private class FolderDiffCallback : DiffUtil.ItemCallback<File>() {
|
||||
@@ -45,9 +93,7 @@ class FolderAdapter(
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: File, newItem: File): Boolean {
|
||||
return oldItem.name == newItem.name &&
|
||||
oldItem.lastModified() == newItem.lastModified() &&
|
||||
oldItem.length() == newItem.length()
|
||||
return oldItem.name == newItem.name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import android.Manifest
|
||||
import androidx.core.content.FileProvider
|
||||
import devs.org.calculator.R
|
||||
|
||||
class FileManager(private val context: Context, private val lifecycleOwner: LifecycleOwner) {
|
||||
private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest>
|
||||
@@ -72,14 +73,12 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
|
||||
return typeDir.listFiles()?.filterNotNull()?.filter { it.name != ".nomedia" } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun copyFileToHiddenDir(uri: Uri, type: FileType, currentDir: File? = null): File? {
|
||||
private fun copyFileToHiddenDir(uri: Uri, folderName: File, currentDir: File? = null): File? {
|
||||
return try {
|
||||
val contentResolver = context.contentResolver
|
||||
|
||||
// Get the target directory
|
||||
val targetDir = currentDir ?: File(Environment.getExternalStorageDirectory(), "$HIDDEN_DIR/${type.dirName}")
|
||||
targetDir.mkdirs()
|
||||
File(targetDir, ".nomedia").createNewFile()
|
||||
// Get the target directory (i am using the current opened folder as target folder)
|
||||
val targetDir = folderName
|
||||
|
||||
// Create target file
|
||||
val mimeType = contentResolver.getType(uri)
|
||||
@@ -153,6 +152,64 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun unHideFile(file: File, onSuccess: (() -> Unit)? = null, onError: ((String) -> Unit)? = null) {
|
||||
lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
// Create target directory (Downloads)
|
||||
val targetDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
targetDir.mkdirs()
|
||||
|
||||
// Create target file with same name or timestamp
|
||||
val targetFile = File(targetDir, file.name)
|
||||
|
||||
// If file with same name exists, add timestamp
|
||||
val finalTargetFile = if (targetFile.exists()) {
|
||||
val nameWithoutExt = file.nameWithoutExtension
|
||||
val extension = file.extension
|
||||
File(targetDir, "${nameWithoutExt}_${System.currentTimeMillis()}.${extension}")
|
||||
} else {
|
||||
targetFile
|
||||
}
|
||||
|
||||
// Copy file content
|
||||
file.copyTo(finalTargetFile, overwrite = false)
|
||||
|
||||
// Verify copy success
|
||||
if (finalTargetFile.exists() && finalTargetFile.length() > 0) {
|
||||
// Delete original hidden file
|
||||
if (file.delete()) {
|
||||
// Trigger media scan for the new file
|
||||
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
|
||||
mediaScanIntent.data = Uri.fromFile(finalTargetFile)
|
||||
context.sendBroadcast(mediaScanIntent)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, context.getString(R.string.file_unhidden_successfully), Toast.LENGTH_SHORT).show()
|
||||
onSuccess?.invoke() // Call success callback
|
||||
}
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, "File copied but failed to remove from hidden folder", Toast.LENGTH_SHORT).show()
|
||||
onError?.invoke("Failed to remove from hidden folder")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, "Failed to copy file", Toast.LENGTH_SHORT).show()
|
||||
onError?.invoke("Failed to copy file")
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(context, "Error unhiding file: ${e.message}", Toast.LENGTH_LONG).show()
|
||||
onError?.invoke(e.message ?: "Unknown error")
|
||||
}
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deletePhotoFromExternalStorage(photoUri: Uri) {
|
||||
withContext(Dispatchers.IO) {
|
||||
@@ -284,7 +341,7 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
|
||||
|
||||
suspend fun processMultipleFiles(
|
||||
uriList: List<Uri>,
|
||||
fileType: FileType,
|
||||
fileType: File,
|
||||
callback: FileProcessCallback,
|
||||
currentDir: File? = null
|
||||
) {
|
||||
|
||||
@@ -24,13 +24,11 @@ class FolderManager(private val context: Context) {
|
||||
fun deleteFolder(folder: File): Boolean {
|
||||
return try {
|
||||
if (folder.exists() && folder.isDirectory) {
|
||||
// Delete all files in the folder first
|
||||
folder.listFiles()?.forEach { file ->
|
||||
if (file.isFile) {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
// Then delete the folder itself
|
||||
folder.delete()
|
||||
} else {
|
||||
false
|
||||
|
||||
11
app/src/main/res/drawable/ic_setting.xml
Normal file
11
app/src/main/res/drawable/ic_setting.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillAlpha="0.15" android:fillColor="#00363853" android:pathData="M17.88,18.6C17.88,19.926 16.806,21 15.48,21C14.155,21 13.08,19.926 13.08,18.6C13.08,17.274 14.155,16.2 15.48,16.2C16.806,16.2 17.88,17.274 17.88,18.6Z"/>
|
||||
|
||||
<path android:fillAlpha="0.15" android:fillColor="#00363853" android:pathData="M9.48,12C9.48,13.325 8.405,14.4 7.08,14.4C5.755,14.4 4.68,13.325 4.68,12C4.68,10.675 5.755,9.6 7.08,9.6C8.405,9.6 9.48,10.675 9.48,12Z"/>
|
||||
|
||||
<path android:fillAlpha="0.15" android:fillColor="#00363853" android:pathData="M17.88,5.4C17.88,6.725 16.806,7.8 15.48,7.8C14.155,7.8 13.08,6.725 13.08,5.4C13.08,4.075 14.155,3 15.48,3C16.806,3 17.88,4.075 17.88,5.4Z"/>
|
||||
|
||||
<path android:fillColor="#00000000" android:pathData="M18.48,18.537H21M4.68,12L3,12.044M4.68,12C4.68,13.325 5.755,14.4 7.08,14.4C8.405,14.4 9.48,13.325 9.48,12C9.48,10.675 8.405,9.6 7.08,9.6C5.755,9.6 4.68,10.675 4.68,12ZM10.169,12.044H21M12.801,5.551L3,5.551M21,5.551H18.48M3,18.537H12.801M17.88,18.6C17.88,19.926 16.806,21 15.48,21C14.155,21 13.08,19.926 13.08,18.6C13.08,17.274 14.155,16.2 15.48,16.2C16.806,16.2 17.88,17.274 17.88,18.6ZM17.88,5.4C17.88,6.725 16.806,7.8 15.48,7.8C14.155,7.8 13.08,6.725 13.08,5.4C13.08,4.075 14.155,3 15.48,3C16.806,3 17.88,4.075 17.88,5.4Z" android:strokeColor="@color/textColor" android:strokeLineCap="round" android:strokeWidth="1.5"/>
|
||||
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/selected.xml
Normal file
12
app/src/main/res/drawable/selected.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="800dp"
|
||||
android:height="800dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M512,512m-448,0a448,448 0,1 0,896 0,448 448,0 1,0 -896,0Z"
|
||||
android:fillColor="#00ffffff"/>
|
||||
<path
|
||||
android:pathData="M738.1,311.5L448,601.6l-119.5,-119.5 -59.7,59.7 179.2,179.2 349.9,-349.9z"
|
||||
android:fillColor="@color/textColor"/>
|
||||
</vector>
|
||||
@@ -14,6 +14,8 @@
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/toolBar"
|
||||
android:layout_marginTop="25dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
@@ -29,20 +31,29 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Folder Name"
|
||||
android:text="@string/hidden_space"
|
||||
android:textSize="18sp"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/folderName"/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_setting"
|
||||
android:scaleType="fitCenter"
|
||||
android:background="#00000000"
|
||||
android:padding="9dp"
|
||||
android:id="@+id/settings"/>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolBar">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
@@ -112,8 +123,8 @@
|
||||
app:fabCustomSize="51dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addDocument"
|
||||
app:layout_constraintEnd_toEndOf="@+id/fabExpend"
|
||||
app:layout_constraintStart_toStartOf="@+id/fabExpend" />
|
||||
app:layout_constraintEnd_toEndOf="@+id/addDocument"
|
||||
app:layout_constraintStart_toStartOf="@+id/addDocument" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addDocument"
|
||||
@@ -125,8 +136,8 @@
|
||||
app:fabCustomSize="54dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/fabExpend"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addFolder"
|
||||
app:layout_constraintStart_toStartOf="@+id/addFolder" />
|
||||
app:layout_constraintEnd_toEndOf="@+id/fabExpend"
|
||||
app:layout_constraintStart_toStartOf="@+id/fabExpend" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addFolder"
|
||||
@@ -138,8 +149,8 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:fabCustomSize="57dp"
|
||||
/>
|
||||
app:fabCustomSize="57dp" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabExpend"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -153,4 +164,16 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/deleteSelected"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:fabCustomSize="57dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
app:cardCornerRadius="8dp">
|
||||
|
||||
<devs.org.calculator.views.SquareImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -1,48 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout 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="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/folderIcon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_folder" />
|
||||
<LinearLayout
|
||||
android:id="@+id/selectedLayer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:alpha="0.2"
|
||||
android:background="?attr/colorControlNormal"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/folderName"
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:textSize="14sp" />
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/folderIcon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_folder" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<TextView
|
||||
android:id="@+id/folderName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:padding="3dp"
|
||||
android:visibility="gone"
|
||||
android:src="@drawable/selected"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</FrameLayout>
|
||||
35
app/src/main/res/layout/proccessing_dialog.xml
Normal file
35
app/src/main/res/layout/proccessing_dialog.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="15dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hiding_files"
|
||||
android:padding="8dp"
|
||||
android:textSize="20sp"/>
|
||||
|
||||
<com.airbnb.lottie.LottieAnimationView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
app:lottie_fileName="hiding_files.json"
|
||||
app:lottie_autoPlay="true"
|
||||
android:scaleX="1.2"
|
||||
android:scaleY="1.2"
|
||||
android:scaleType="centerCrop"
|
||||
app:lottie_loop="true"/>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="25dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:indeterminate="true"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -8,27 +8,33 @@
|
||||
android:layout_margin="4dp"
|
||||
app:cardCornerRadius="8dp">
|
||||
|
||||
|
||||
<com.jsibbold.zoomage.ZoomageView
|
||||
android:id="@+id/imageView"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:zoomage_restrictBounds="false"
|
||||
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"
|
||||
app:zoomage_maxScale="8"
|
||||
/>
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
<com.jsibbold.zoomage.ZoomageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:zoomage_restrictBounds="false"
|
||||
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"
|
||||
app:zoomage_maxScale="8"
|
||||
/>
|
||||
|
||||
<VideoView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/videoView"/>
|
||||
<VideoView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/videoView"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/audioBg"
|
||||
|
||||
@@ -10,13 +10,9 @@
|
||||
<string name="rename_file">Rename File</string>
|
||||
<string name="share_file">Share File</string>
|
||||
<string name="add_document">Add Document</string>
|
||||
<string name="failed_to_hide_audio">Failed to hide Audios</string>
|
||||
<string name="failed_to_hide_documents">Failed to hide Documents</string>
|
||||
<string name="no_files_selected">No files selected</string>
|
||||
<string name="documents_hidden_successfully"> Documents hidden successfully</string>
|
||||
<string name="failed_to_hide_unhide_photo">Failed to hide/unhide photo</string>
|
||||
<string name="images_hidden_successfully"> Images hidden successfully</string>
|
||||
<string name="failed_to_hide_images">Failed to hide images</string>
|
||||
<string name="documents_hidden_successfully">Files hidden successfully</string>
|
||||
<string name="failed_to_hide_files">Failed to hide files</string>
|
||||
<string name="storage_permissions_granted">Storage permissions granted</string>
|
||||
<string name="storage_permissions_denied">Storage permissions denied</string>
|
||||
<string name="preview_images">Preview Images</string>
|
||||
@@ -47,37 +43,22 @@
|
||||
<string name="answer_cannot_be_empty">Answer cannot be empty!</string>
|
||||
<string name="password_successfully_reset">Password successfully reset.</string>
|
||||
<string name="invalid_answer">Invalid answer!</string>
|
||||
<string name="videos_hidden_successfully"> Videos hidden successfully</string>
|
||||
<string name="failed_to_hide_videos">Failed to hide videos</string>
|
||||
<string name="image">IMAGE</string>
|
||||
<string name="video">VIDEO</string>
|
||||
<string name="audio">AUDIO</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="create">Create</string>
|
||||
<string name="delete_folder">Delete Folder</string>
|
||||
<string name="rename">Rename</string>
|
||||
<string name="cannot_delete_folder">Cannot Delete Folder</string>
|
||||
<string name="document">DOCUMENT</string>
|
||||
<string name="no_audio_player_found">No audio player found!</string>
|
||||
<string name="no_suitable_app_found_to_open_this_document">No suitable app found to open this document!</string>
|
||||
<string name="unknown_file">Unknown File</string>
|
||||
<string name="details"> DETAILS</string>
|
||||
<string name="audio_hidded_successfully">Audios hidden successfully</string>
|
||||
<string name="no_items_available_add_one_by_clicking_on_the_plus_button">No Items Available, Add one by clicking on the</string>
|
||||
<string name="now_enter_button">Now Enter \'=\' button</string>
|
||||
<string name="enter_123456">Enter 123456</string>
|
||||
<string name="create_folder">Create Folder</string>
|
||||
<string name="enter_folder_name">Enter folder name</string>
|
||||
<string name="folder_already_exists">Folder already exists</string>
|
||||
<string name="folder_options">Folder Options</string>
|
||||
<string name="rename_folder">Rename Folder</string>
|
||||
<string name="enter_new_folder_name">Enter new folder name</string>
|
||||
<string name="failed_to_create_folder">Failed to create folder</string>
|
||||
<string name="are_you_sure_you_want_to_delete_this_folder">Are you sure you want to delete this folder?</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="error_loading_files">Error loading files</string>
|
||||
<string name="delete_items">Delete Items</string>
|
||||
<string name="are_you_sure_you_want_to_delete_selected_items">Are you sure you want to delete selected items?</string>
|
||||
<string name="items_deleted_successfully">Items deleted successfully</string>
|
||||
<string name="now_enter_button">Now Enter \'=\' button</string>
|
||||
<string name="delete_items">Delete Folder</string>
|
||||
<string name="are_you_sure_you_want_to_delete_selected_items">Are you sure you want to delete selected Folders?</string>
|
||||
<string name="folder_deleted_successfully">Folder deleted successfully</string>
|
||||
<string name="some_items_could_not_be_deleted">Some items could not be deleted</string>
|
||||
<string name="hidden_space">Hidden Space</string>
|
||||
<string name="there_was_a_problem_in_the_folder">There was a problem in the Folder</string>
|
||||
<string name="file_unhidden_successfully">File Will Now Show In Gallery</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user