diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f7cd6f2..7450a63 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,19 +20,21 @@ android { buildTypes { release { isMinifyEnabled = true + isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } debug { - isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } + + compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -43,6 +45,21 @@ android { buildFeatures{ viewBinding = true } + + packaging { + resources { + excludes += listOf( + "META-INF/DEPENDENCIES", + "META-INF/LICENSE", + "META-INF/LICENSE.txt", + "META-INF/license.txt", + "META-INF/NOTICE", + "META-INF/NOTICE.txt", + "META-INF/notice.txt", + "META-INF/ASL2.0" + ) + } + } } dependencies { @@ -64,4 +81,5 @@ dependencies { implementation(libs.photoview) implementation(libs.androidx.viewpager) implementation(libs.zoomage) + implementation(libs.lottie) } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e00f4d9..e5484f0 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -67,4 +67,4 @@ # Keep specific activities with special code in onCreate -keepclassmembers class * extends android.app.Activity { public void onCreate(android.os.Bundle); -} \ No newline at end of file +} diff --git a/app/src/main/assets/hiding_files.json b/app/src/main/assets/hiding_files.json new file mode 100644 index 0000000..88c5731 --- /dev/null +++ b/app/src/main/assets/hiding_files.json @@ -0,0 +1 @@ +{"nm":"Comp 1","ddd":0,"h":500,"w":500,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":386.999977966587,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-58.5,-39.25,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.48,"y":0.033},"i":{"x":0.52,"y":0.96},"s":[249.5,272.75,0],"t":13,"ti":[0,0,0],"to":[0,0.333,0]},{"o":{"x":0.48,"y":0.053},"i":{"x":0.52,"y":0.96},"s":[249.5,274.75,0],"t":18,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.48,"y":0.033},"i":{"x":0.52,"y":0.96},"s":[249.5,272.75,0],"t":22,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.48,"y":0.033},"i":{"x":0.52,"y":0.96},"s":[249.5,274.75,0],"t":27,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.48,"y":0.067},"i":{"x":0.52,"y":0.96},"s":[249.5,272.75,0],"t":32,"ti":[0,0,0],"to":[0,0,0]},{"o":{"x":0.48,"y":0.067},"i":{"x":0.52,"y":0.96},"s":[249.5,274.75,0],"t":37,"ti":[0,0.333,0],"to":[0,0,0]},{"s":[249.5,272.75,0],"t":41.9999976087769}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-50.5,-90],[-129,-88.5],[-129,11.5],[12,11.5],[12,-69],[-29.5,-69]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":7,"ix":5},"c":{"a":0,"k":[0,0.4235,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-127.5,-88.5],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.10980392156862745,0.4666666666666667,1,0.5,0.18823529411764706,0.39215686274509803,1,1,0.27058823529411763,0.3215686274509804,1],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[8,9.5],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"rd","bm":0,"hd":false,"mn":"ADBE Vector Filter - RC","nm":"Round Corners 1","ix":2,"r":{"a":0,"k":10,"ix":1}}],"ind":1},{"ty":4,"nm":"Shape Layer 3","sr":1,"st":0,"op":386.999977966587,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[-32,-48.922,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[0],"t":0},{"o":{"x":0.48,"y":0},"i":{"x":0.833,"y":1},"s":[100],"t":11},{"o":{"x":0.167,"y":0},"i":{"x":0.52,"y":1},"s":[100],"t":25},{"s":[0],"t":34.9999980073141}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[47.25,-61.5],[47.25,61.5],[-47.25,61.5],[-47.25,-36],[-26.5,-61.5]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":7,"ix":5},"c":{"a":0,"k":[0,0.4235,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[0,62],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.7607843137254902,0.8549019607843137,1,0.5,0.7764705882352941,0.8313725490196079,1,1,0.792156862745098,0.807843137254902,1],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[1,-62],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":1,"k":[{"o":{"x":0.48,"y":0.049},"i":{"x":0,"y":1},"s":[-8,-118.5],"t":0,"ti":[-0.167,-17.167],"to":[0.167,17.167]},{"s":[-7,-15.5],"t":26.9999984627852}],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"rd","bm":0,"hd":false,"mn":"ADBE Vector Filter - RC","nm":"Round Corners 1","ix":2,"r":{"a":0,"k":10,"ix":1}}],"ind":2,"parent":1},{"ty":4,"nm":"Shape Layer 4","sr":1,"st":5.9999996583967,"op":392.999977624984,"ip":5.9999996583967,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[-44.5,-39.922,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[0],"t":6},{"o":{"x":0.48,"y":0},"i":{"x":0.833,"y":1},"s":[100],"t":17},{"o":{"x":0.167,"y":0},"i":{"x":0.52,"y":1},"s":[100],"t":29},{"s":[0],"t":38.9999977795785}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[47.25,-61.5],[47.25,61.5],[-47.25,61.5],[-47.25,-36],[-26.5,-61.5]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":7,"ix":5},"c":{"a":0,"k":[0,0.4235,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[0,62],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.6901960784313725,0.8156862745098039,1,0.5,0.6470588235294118,0.7215686274509804,0.9411764705882353,1,0.6078431372549019,0.6235294117647059,0.8823529411764706],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[1,-62],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":1,"k":[{"o":{"x":0.48,"y":0.05},"i":{"x":0,"y":1},"s":[-8,-118.5],"t":6,"ti":[-0.167,-16.75],"to":[0.167,16.75]},{"s":[-7,-18],"t":32.9999981211819}],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"rd","bm":0,"hd":false,"mn":"ADBE Vector Filter - RC","nm":"Round Corners 1","ix":2,"r":{"a":0,"k":10,"ix":1}}],"ind":3,"parent":1},{"ty":4,"nm":"Shape Layer 5","sr":1,"st":10.9999993737273,"op":397.999977340315,"ip":10.9999993737273,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[-59.5,-35.422,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[0],"t":11},{"o":{"x":0.48,"y":0},"i":{"x":0.833,"y":1},"s":[100],"t":22},{"o":{"x":0.167,"y":0},"i":{"x":0.52,"y":1},"s":[100],"t":34},{"s":[0],"t":43.9999974949091}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[47.25,-61.5],[47.25,61.5],[-47.25,61.5],[-47.25,-36],[-26.5,-61.5]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":7,"ix":5},"c":{"a":0,"k":[0,0.4235,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[0,62],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.5294117647058824,0.7176470588235294,1,0.5,0.4745098039215686,0.5843137254901961,0.9411764705882353,1,0.4196078431372549,0.45098039215686275,0.8823529411764706],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[1,-62],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":1,"k":[{"o":{"x":0.48,"y":0.049},"i":{"x":0,"y":1},"s":[-8,-118.5],"t":11,"ti":[-0.167,-17.167],"to":[0.167,17.167]},{"s":[-7,-15.5],"t":37.9999978365124}],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"rd","bm":0,"hd":false,"mn":"ADBE Vector Filter - RC","nm":"Round Corners 1","ix":2,"r":{"a":0,"k":10,"ix":1}}],"ind":4,"parent":1},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":386.999977966587,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[-58,-20,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":4,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[12.5,-86],[-78.625,-86],[-70.75,22.875],[61.5,-39.5]]},"ix":2}},{"ty":"rd","bm":0,"hd":false,"mn":"ADBE Vector Filter - RC","nm":"Round Corners 1","ix":2,"r":{"a":0,"k":10,"ix":1}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":7,"ix":5},"c":{"a":0,"k":[0,0.4235,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-0.5,-14],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.0196078431372549,0.30980392156862746,0.7411764705882353,0.5,0.08627450980392157,0.24313725490196078,0.6588235294117647,1,0.14901960784313725,0.1803921568627451,0.5764705882352941],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-76,-81],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5,"parent":1}],"v":"5.5.5","fr":30.0169982910156,"op":54.9999968686364,"ip":0,"assets":[]} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/HiddenActivity.kt b/app/src/main/java/devs/org/calculator/activities/HiddenActivity.kt index 6b07e0e..7cdc89f 100644 --- a/app/src/main/java/devs/org/calculator/activities/HiddenActivity.kt +++ b/app/src/main/java/devs/org/calculator/activities/HiddenActivity.kt @@ -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 + 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() + + 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) { + 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, - 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() } diff --git a/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt b/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt index d483806..7161ebf 100644 --- a/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt +++ b/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt @@ -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, _ -> diff --git a/app/src/main/java/devs/org/calculator/adapters/FolderAdapter.kt b/app/src/main/java/devs/org/calculator/adapters/FolderAdapter.kt index 75dae84..da5c9db 100644 --- a/app/src/main/java/devs/org/calculator/adapters/FolderAdapter.kt +++ b/app/src/main/java/devs/org/calculator/adapters/FolderAdapter.kt @@ -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(FolderDiffCallback()) { - class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val folderNameTextView: TextView = itemView.findViewById(R.id.folderName) + private val selectedItems = mutableSetOf() + 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 { + 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() { @@ -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 } } } \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/utils/FileManager.kt b/app/src/main/java/devs/org/calculator/utils/FileManager.kt index 28380f8..296da70 100644 --- a/app/src/main/java/devs/org/calculator/utils/FileManager.kt +++ b/app/src/main/java/devs/org/calculator/utils/FileManager.kt @@ -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 @@ -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, - fileType: FileType, + fileType: File, callback: FileProcessCallback, currentDir: File? = null ) { diff --git a/app/src/main/java/devs/org/calculator/utils/FolderManager.kt b/app/src/main/java/devs/org/calculator/utils/FolderManager.kt index 053cf12..b58cb15 100644 --- a/app/src/main/java/devs/org/calculator/utils/FolderManager.kt +++ b/app/src/main/java/devs/org/calculator/utils/FolderManager.kt @@ -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 diff --git a/app/src/main/res/drawable/ic_setting.xml b/app/src/main/res/drawable/ic_setting.xml new file mode 100644 index 0000000..512fdde --- /dev/null +++ b/app/src/main/res/drawable/ic_setting.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/selected.xml b/app/src/main/res/drawable/selected.xml new file mode 100644 index 0000000..35e8a5a --- /dev/null +++ b/app/src/main/res/drawable/selected.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/activity_hidden.xml b/app/src/main/res/layout/activity_hidden.xml index 6dcf5e5..dfcc86b 100644 --- a/app/src/main/res/layout/activity_hidden.xml +++ b/app/src/main/res/layout/activity_hidden.xml @@ -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 @@ + + + app:layout_constraintTop_toBottomOf="@+id/toolBar"> @@ -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" /> + app:layout_constraintEnd_toEndOf="@+id/fabExpend" + app:layout_constraintStart_toStartOf="@+id/fabExpend" /> + app:fabCustomSize="57dp" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_file.xml b/app/src/main/res/layout/item_file.xml deleted file mode 100644 index 831e46a..0000000 --- a/app/src/main/res/layout/item_file.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_folder.xml b/app/src/main/res/layout/item_folder.xml index 5939ad4..e37c514 100644 --- a/app/src/main/res/layout/item_folder.xml +++ b/app/src/main/res/layout/item_folder.xml @@ -1,48 +1,73 @@ - + android:layout_height="wrap_content"> - + - + android:layout_height="wrap_content"> - + - + 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"> - + - + - - - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/proccessing_dialog.xml b/app/src/main/res/layout/proccessing_dialog.xml new file mode 100644 index 0000000..da9a281 --- /dev/null +++ b/app/src/main/res/layout/proccessing_dialog.xml @@ -0,0 +1,35 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/viewpager_items.xml b/app/src/main/res/layout/viewpager_items.xml index 16e4fc9..2e2fc38 100644 --- a/app/src/main/res/layout/viewpager_items.xml +++ b/app/src/main/res/layout/viewpager_items.xml @@ -8,27 +8,33 @@ android:layout_margin="4dp" app:cardCornerRadius="8dp"> - - + android:gravity="center" + android:orientation="vertical"> + - + + Rename File Share File Add Document - Failed to hide Audios - Failed to hide Documents No files selected - Documents hidden successfully - Failed to hide/unhide photo - Images hidden successfully - Failed to hide images + Files hidden successfully + Failed to hide files Storage permissions granted Storage permissions denied Preview Images @@ -47,37 +43,22 @@ Answer cannot be empty! Password successfully reset. Invalid answer! - Videos hidden successfully - Failed to hide videos IMAGE VIDEO AUDIO Delete Create - Delete Folder Rename - Cannot Delete Folder DOCUMENT No audio player found! No suitable app found to open this document! - Unknown File - DETAILS - Audios hidden successfully - No Items Available, Add one by clicking on the - Now Enter \'=\' button Enter 123456 - Create Folder - Enter folder name - Folder already exists - Folder Options - Rename Folder - Enter new folder name - Failed to create folder - Are you sure you want to delete this folder? - Yes - Error loading files - Delete Items - Are you sure you want to delete selected items? - Items deleted successfully + Now Enter \'=\' button + Delete Folder + Are you sure you want to delete selected Folders? + Folder deleted successfully Some items could not be deleted + Hidden Space + There was a problem in the Folder + File Will Now Show In Gallery \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ba4b55..292b325 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ junit = "4.13.2" junitVersion = "1.2.1" espressoCore = "3.6.1" appcompat = "1.7.0" +lottie = "6.2.0" material = "1.12.0" activity = "1.9.3" constraintlayout = "2.2.0" @@ -28,6 +29,7 @@ junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +lottie = { module = "com.airbnb.android:lottie", version.ref = "lottie" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }