Changes For Folder Feature
This commit is contained in:
@@ -32,6 +32,9 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Calculator"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".activities.ViewFolderActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".activities.SettingsActivity"
|
||||
android:exported="false" />
|
||||
@@ -50,9 +53,6 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.HiddenVaultActivity"
|
||||
android:exported="true" />
|
||||
<activity
|
||||
android:name=".activities.PreviewActivity"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
package devs.org.calculator
|
||||
|
||||
import android.app.Application
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.google.android.material.color.DynamicColors
|
||||
|
||||
class CalculatorApp : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// Apply dynamic colors to enable Material You theming
|
||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
|
||||
// Initialize theme settings
|
||||
val prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
||||
|
||||
// Apply saved theme mode
|
||||
val themeMode = prefs.getInt("theme_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
AppCompatDelegate.setDefaultNightMode(themeMode)
|
||||
|
||||
// Apply dynamic colors only if dynamic theme is enabled
|
||||
if (prefs.getBoolean("dynamic_theme", true)) {
|
||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,484 +1,530 @@
|
||||
package devs.org.calculator.activities
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
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.view.WindowManager
|
||||
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.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
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.FileProcessCallback
|
||||
import devs.org.calculator.adapters.ListFolderAdapter
|
||||
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 devs.org.calculator.utils.PrefsUtil
|
||||
import java.io.File
|
||||
|
||||
class HiddenActivity : AppCompatActivity() {
|
||||
|
||||
private var isFabOpen = false
|
||||
private lateinit var fabOpen: Animation
|
||||
private lateinit var fabClose: Animation
|
||||
private lateinit var rotateOpen: Animation
|
||||
private lateinit var rotateClose: Animation
|
||||
|
||||
private lateinit var binding: ActivityHiddenBinding
|
||||
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 lateinit var fileManager: FileManager
|
||||
private lateinit var folderManager: FolderManager
|
||||
private lateinit var dialogUtil: DialogUtil
|
||||
private var currentFolder: File? = null
|
||||
private var folderAdapter: FolderAdapter? = null
|
||||
val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
||||
private var listFolderAdapter: ListFolderAdapter? = null
|
||||
private 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 val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
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
|
||||
}
|
||||
companion object {
|
||||
private const val TAG = "HiddenActivity"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
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)
|
||||
rotateOpen = AnimationUtils.loadAnimation(this, R.anim.rotate_open)
|
||||
rotateClose = AnimationUtils.loadAnimation(this, R.anim.rotate_close)
|
||||
|
||||
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
|
||||
// Initialize managers
|
||||
fileManager = FileManager(this, this)
|
||||
folderManager = FolderManager(this)
|
||||
dialogUtil = DialogUtil(this)
|
||||
|
||||
setupInitialUIState()
|
||||
setupClickListeners()
|
||||
setupBackPressedHandler()
|
||||
|
||||
// Initialize permissions and load data
|
||||
fileManager.askPermission(this)
|
||||
|
||||
// Set initial orientation icon based on saved preference
|
||||
refreshCurrentView()
|
||||
}
|
||||
|
||||
private fun setupInitialUIState() {
|
||||
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
binding.deleteSelected.visibility = View.GONE
|
||||
binding.delete.visibility = View.GONE
|
||||
binding.menuButton.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.fabExpend.setOnClickListener {
|
||||
if (isFabOpen) {
|
||||
closeFabs()
|
||||
private fun setupClickListeners() {
|
||||
|
||||
} else {
|
||||
openFabs()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
binding.settings.setOnClickListener {
|
||||
startActivity(Intent(this, SettingsActivity::class.java))
|
||||
}
|
||||
|
||||
binding.addImage.setOnClickListener { openFilePicker("image/*") }
|
||||
binding.addVideo.setOnClickListener { openFilePicker("video/*") }
|
||||
binding.addAudio.setOnClickListener { openFilePicker("audio/*") }
|
||||
|
||||
binding.back.setOnClickListener {
|
||||
if (currentFolder != null) {
|
||||
pressBack()
|
||||
handleBackPress()
|
||||
}
|
||||
|
||||
binding.addFolder.setOnClickListener {
|
||||
createNewFolder()
|
||||
}
|
||||
|
||||
binding.deleteSelected.setOnClickListener {
|
||||
deleteSelectedItems()
|
||||
}
|
||||
|
||||
binding.delete.setOnClickListener {
|
||||
deleteSelectedItems()
|
||||
}
|
||||
|
||||
binding.edit.setOnClickListener {
|
||||
editSelectedFolder()
|
||||
}
|
||||
|
||||
binding.folderOrientation.setOnClickListener {
|
||||
// Switch between grid mode and list mode
|
||||
val currentIsList = PrefsUtil(this).getBoolean("isList", false)
|
||||
val newIsList = !currentIsList
|
||||
|
||||
if (newIsList) {
|
||||
// Switch to list view
|
||||
showListUI()
|
||||
PrefsUtil(this).setBoolean("isList", true)
|
||||
binding.folderOrientation.setImageResource(R.drawable.ic_grid)
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
// Switch to grid view
|
||||
showGridUI()
|
||||
PrefsUtil(this).setBoolean("isList", false)
|
||||
binding.folderOrientation.setImageResource(R.drawable.ic_list)
|
||||
}
|
||||
}
|
||||
binding.addDocument.setOnClickListener { openFilePicker("*/*") }
|
||||
binding.addFolder.setOnClickListener {
|
||||
dialogUtil.createInputDialog(
|
||||
title = "Enter Folder Name To Create",
|
||||
hint = "",
|
||||
callback = object : DialogUtil.InputDialogCallback {
|
||||
override fun onPositiveButtonClicked(input: String) {
|
||||
fileManager.askPermission(this@HiddenActivity)
|
||||
folderManager.createFolder( hiddenDir,input )
|
||||
listFoldersInHiddenDirectory()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fileManager.askPermission(this)
|
||||
private fun showGridUI() {
|
||||
listFoldersInHiddenDirectory()
|
||||
}
|
||||
|
||||
setupDeleteButton()
|
||||
private fun showListUI() {
|
||||
listFoldersInHiddenDirectoryListStyle()
|
||||
}
|
||||
|
||||
pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val clipData = result.data?.clipData
|
||||
val uriList = mutableListOf<Uri>()
|
||||
private fun listFoldersInHiddenDirectoryListStyle() {
|
||||
try {
|
||||
if (!hiddenDir.exists()) {
|
||||
fileManager.getHiddenDirectory()
|
||||
}
|
||||
|
||||
if (clipData != null) {
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
val uri = clipData.getItemAt(i).uri
|
||||
uriList.add(uri)
|
||||
}
|
||||
if (hiddenDir.exists() && hiddenDir.isDirectory) {
|
||||
val folders = folderManager.getFoldersInDirectory(hiddenDir)
|
||||
|
||||
if (folders.isNotEmpty()) {
|
||||
showFolderListStyle(folders)
|
||||
} else {
|
||||
result.data?.data?.let { uriList.add(it) }
|
||||
showEmptyState()
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Hidden directory is not accessible: ${hiddenDir.absolutePath}")
|
||||
showEmptyState()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error listing folders: ${e.message}")
|
||||
showEmptyState()
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
private fun setupBackPressedHandler() {
|
||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handleBackPress()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onFileProcessFailed() {
|
||||
Toast.makeText(this@HiddenActivity,
|
||||
getString(R.string.failed_to_hide_files), Toast.LENGTH_SHORT).show()
|
||||
dismissCustomDialog()
|
||||
}
|
||||
|
||||
})
|
||||
}else{
|
||||
private fun createNewFolder() {
|
||||
dialogUtil.createInputDialog(
|
||||
title = "Enter Folder Name To Create",
|
||||
hint = "",
|
||||
callback = object : DialogUtil.InputDialogCallback {
|
||||
override fun onPositiveButtonClicked(input: String) {
|
||||
if (input.trim().isNotEmpty()) {
|
||||
try {
|
||||
folderManager.createFolder(hiddenDir, input.trim())
|
||||
refreshCurrentView()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error creating folder: ${e.message}")
|
||||
Toast.makeText(
|
||||
this@HiddenActivity,
|
||||
getString(R.string.there_was_a_problem_in_the_folder),
|
||||
"Failed to create 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()
|
||||
}
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupFlagSecure()
|
||||
}
|
||||
|
||||
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 setupFlagSecure() {
|
||||
val prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
||||
if (prefs.getBoolean("screenshot_restriction", true)) {
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_SECURE,
|
||||
WindowManager.LayoutParams.FLAG_SECURE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFilePicker(mimeType: String) {
|
||||
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)
|
||||
}
|
||||
pickImageLauncher.launch(intent)
|
||||
}
|
||||
|
||||
private fun listFoldersInHiddenDirectory() {
|
||||
if (hiddenDir.exists() && hiddenDir.isDirectory) {
|
||||
val folders = folderManager.getFoldersInDirectory(hiddenDir)
|
||||
|
||||
if (folders.isNotEmpty()) {
|
||||
binding.noItems.visibility = View.GONE
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
|
||||
// Initialize adapter only once
|
||||
if (folderAdapter == null) {
|
||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
|
||||
folderAdapter = FolderAdapter(
|
||||
onFolderClick = { clickedFolder ->
|
||||
openFolder(clickedFolder)
|
||||
},
|
||||
onFolderLongClick = { folder ->
|
||||
// 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
|
||||
}
|
||||
|
||||
// Submit new list to adapter - DiffUtil will handle the comparison
|
||||
folderAdapter?.submitList(folders)
|
||||
} else {
|
||||
binding.noItems.visibility = View.VISIBLE
|
||||
binding.recyclerView.visibility = View.GONE
|
||||
try {
|
||||
if (!hiddenDir.exists()) {
|
||||
fileManager.getHiddenDirectory()
|
||||
}
|
||||
} else if (!hiddenDir.exists()) {
|
||||
fileManager.getHiddenDirectory()
|
||||
} else {
|
||||
Log.e("HiddenActivity", "Hidden directory is not a directory: ${hiddenDir.absolutePath}")
|
||||
|
||||
if (hiddenDir.exists() && hiddenDir.isDirectory) {
|
||||
val folders = folderManager.getFoldersInDirectory(hiddenDir)
|
||||
|
||||
if (folders.isNotEmpty()) {
|
||||
showFolderList(folders)
|
||||
} else {
|
||||
showEmptyState()
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Hidden directory is not accessible: ${hiddenDir.absolutePath}")
|
||||
showEmptyState()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error listing folders: ${e.message}")
|
||||
showEmptyState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFolder(folder: File) {
|
||||
Log.d("HiddenActivity", "Opening folder: ${folder.name}")
|
||||
currentFolder = folder
|
||||
binding.addFolder.visibility = View.GONE
|
||||
binding.fabExpend.visibility = View.VISIBLE
|
||||
private fun showFolderList(folders: List<File>) {
|
||||
binding.noItems.visibility = View.GONE
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
|
||||
// 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
|
||||
// Clear the existing adapter to avoid conflicts
|
||||
listFolderAdapter = null
|
||||
|
||||
if (files.isNotEmpty()) {
|
||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
|
||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 2)
|
||||
folderAdapter = FolderAdapter(
|
||||
onFolderClick = { clickedFolder ->
|
||||
startActivity(Intent(this,ViewFolderActivity::class.java).putExtra("folder",clickedFolder.toString()))
|
||||
},
|
||||
onFolderLongClick = {
|
||||
enterFolderSelectionMode()
|
||||
},
|
||||
onSelectionModeChanged = { isSelectionMode ->
|
||||
handleFolderSelectionModeChange(isSelectionMode)
|
||||
},
|
||||
onSelectionCountChanged = { selectedCount ->
|
||||
updateEditButtonVisibility()
|
||||
}
|
||||
)
|
||||
binding.recyclerView.adapter = folderAdapter
|
||||
folderAdapter?.submitList(folders)
|
||||
|
||||
val fileAdapter = FileAdapter(this, this, folder).apply {
|
||||
fileOperationCallback = object : FileAdapter.FileOperationCallback {
|
||||
override fun onFileDeleted(file: File) {
|
||||
// Refresh the file list
|
||||
refreshCurrentFolder()
|
||||
// Ensure proper icon state for folder view
|
||||
if (folderAdapter?.isInSelectionMode() != true) {
|
||||
showFolderViewIcons()
|
||||
}
|
||||
}
|
||||
private fun showFolderListStyle(folders: List<File>) {
|
||||
binding.noItems.visibility = View.GONE
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
|
||||
// Clear the existing adapter to avoid conflicts
|
||||
folderAdapter = null
|
||||
|
||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 1)
|
||||
listFolderAdapter = ListFolderAdapter(
|
||||
onFolderClick = { clickedFolder ->
|
||||
startActivity(Intent(this,ViewFolderActivity::class.java).putExtra("folder",clickedFolder.toString()))
|
||||
},
|
||||
onFolderLongClick = {
|
||||
enterFolderSelectionMode()
|
||||
},
|
||||
onSelectionModeChanged = { isSelectionMode ->
|
||||
handleFolderSelectionModeChange(isSelectionMode)
|
||||
},
|
||||
onSelectionCountChanged = { selectedCount ->
|
||||
updateEditButtonVisibility()
|
||||
}
|
||||
)
|
||||
binding.recyclerView.adapter = listFolderAdapter
|
||||
listFolderAdapter?.submitList(folders)
|
||||
|
||||
// Ensure proper icon state for folder view
|
||||
if (listFolderAdapter?.isInSelectionMode() != true) {
|
||||
showFolderViewIcons()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateEditButtonVisibility() {
|
||||
val selectedCount = when {
|
||||
folderAdapter != null -> folderAdapter?.getSelectedItems()?.size ?: 0
|
||||
listFolderAdapter != null -> listFolderAdapter?.getSelectedItems()?.size ?: 0
|
||||
else -> 0
|
||||
}
|
||||
binding.edit.visibility = if (selectedCount == 1) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun showEmptyState() {
|
||||
binding.noItems.visibility = View.VISIBLE
|
||||
binding.recyclerView.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun enterFolderSelectionMode() {
|
||||
showFolderSelectionIcons()
|
||||
}
|
||||
|
||||
|
||||
private fun refreshCurrentView() {
|
||||
val isList = PrefsUtil(this).getBoolean("isList", false)
|
||||
if (isList) {
|
||||
binding.folderOrientation.setImageResource(R.drawable.ic_grid)
|
||||
listFoldersInHiddenDirectoryListStyle()
|
||||
} else {
|
||||
binding.folderOrientation.setImageResource(R.drawable.ic_list)
|
||||
listFoldersInHiddenDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun deleteSelectedItems() {
|
||||
deleteSelectedFolders()
|
||||
}
|
||||
|
||||
private fun deleteSelectedFolders() {
|
||||
val selectedFolders = when {
|
||||
folderAdapter != null -> folderAdapter?.getSelectedItems() ?: emptyList()
|
||||
listFolderAdapter != null -> listFolderAdapter?.getSelectedItems() ?: emptyList()
|
||||
else -> 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() {
|
||||
performFolderDeletion(selectedFolders)
|
||||
}
|
||||
|
||||
override fun onFileRenamed(oldFile: File, newFile: File) {
|
||||
// Refresh the file list
|
||||
refreshCurrentFolder()
|
||||
override fun onNegativeButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun onRefreshNeeded() {
|
||||
// Refresh the file list
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
override fun onSelectionModeChanged(
|
||||
isSelectionMode: Boolean,
|
||||
selectedCount: Int
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
override fun onSelectionCountChanged(selectedCount: Int) {
|
||||
|
||||
|
||||
override fun onNaturalButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
submitList(files)
|
||||
private fun performFolderDeletion(selectedFolders: List<File>) {
|
||||
var allDeleted = true
|
||||
selectedFolders.forEach { folder ->
|
||||
if (!folderManager.deleteFolder(folder)) {
|
||||
allDeleted = false
|
||||
Log.e(TAG, "Failed to delete folder: ${folder.name}")
|
||||
}
|
||||
}
|
||||
|
||||
binding.recyclerView.adapter = fileAdapter
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
binding.noItems.visibility = View.GONE
|
||||
val message = if (allDeleted) {
|
||||
getString(R.string.folder_deleted_successfully)
|
||||
} else {
|
||||
binding.recyclerView.visibility = View.GONE
|
||||
binding.noItems.visibility = View.VISIBLE
|
||||
getString(R.string.some_items_could_not_be_deleted)
|
||||
}
|
||||
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
|
||||
// Clear selection from both adapters
|
||||
folderAdapter?.clearSelection()
|
||||
listFolderAdapter?.clearSelection()
|
||||
|
||||
// This will trigger the selection mode change callback and show proper icons
|
||||
exitFolderSelectionMode()
|
||||
|
||||
// Refresh the current view based on orientation
|
||||
refreshCurrentView()
|
||||
}
|
||||
|
||||
private fun refreshCurrentFolder() {
|
||||
currentFolder?.let { folder ->
|
||||
val files = folderManager.getFilesInFolder(folder)
|
||||
(binding.recyclerView.adapter as? FileAdapter)?.submitList(files)
|
||||
private fun handleBackPress() {
|
||||
|
||||
if (files.isEmpty()) {
|
||||
binding.recyclerView.visibility = View.GONE
|
||||
binding.noItems.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
binding.noItems.visibility = View.GONE
|
||||
}
|
||||
|
||||
// Check if folder adapters are in selection mode
|
||||
if (folderAdapter?.onBackPressed() == true || listFolderAdapter?.onBackPressed() == true) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFabs() {
|
||||
binding.addImage.startAnimation(fabOpen)
|
||||
binding.addVideo.startAnimation(fabOpen)
|
||||
binding.addAudio.startAnimation(fabOpen)
|
||||
binding.addDocument.startAnimation(fabOpen)
|
||||
binding.addFolder.startAnimation(fabOpen)
|
||||
binding.fabExpend.startAnimation(rotateOpen)
|
||||
|
||||
binding.addImage.visibility = View.VISIBLE
|
||||
binding.addVideo.visibility = View.VISIBLE
|
||||
binding.addAudio.visibility = View.VISIBLE
|
||||
binding.addDocument.visibility = View.VISIBLE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
|
||||
isFabOpen = true
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
binding.fabExpend.setImageResource(R.drawable.wrong)
|
||||
},200)
|
||||
}
|
||||
|
||||
private fun closeFabs() {
|
||||
binding.addImage.startAnimation(fabClose)
|
||||
binding.addVideo.startAnimation(fabClose)
|
||||
binding.addAudio.startAnimation(fabClose)
|
||||
binding.addDocument.startAnimation(fabClose)
|
||||
binding.addFolder.startAnimation(fabClose)
|
||||
binding.fabExpend.startAnimation(rotateClose)
|
||||
|
||||
binding.addImage.visibility = View.INVISIBLE
|
||||
binding.addVideo.visibility = View.INVISIBLE
|
||||
binding.addAudio.visibility = View.INVISIBLE
|
||||
binding.addDocument.visibility = View.INVISIBLE
|
||||
binding.addFolder.visibility = View.INVISIBLE
|
||||
|
||||
isFabOpen = false
|
||||
binding.fabExpend.setImageResource(R.drawable.ic_add)
|
||||
}
|
||||
|
||||
|
||||
private fun getFileNameFromUri(uri: Uri): String? {
|
||||
var name: String? = null
|
||||
val cursor = contentResolver.query(uri, null, null, null, null)
|
||||
cursor?.use { it ->
|
||||
val nameIndex = it.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
|
||||
if (nameIndex != -1) {
|
||||
it.moveToFirst()
|
||||
name = it.getString(nameIndex)
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
override fun onNegativeButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun onNaturalButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
// Handle navigation back
|
||||
if (currentFolder != null) {
|
||||
pressBack()
|
||||
navigateBackToFolders()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateBackToFolders() {
|
||||
currentFolder = null
|
||||
|
||||
// Clean up file adapter
|
||||
|
||||
refreshCurrentView()
|
||||
|
||||
binding.folderName.text = getString(R.string.hidden_space)
|
||||
|
||||
// Set proper icons for folder view
|
||||
showFolderViewIcons()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
|
||||
// Remove any pending callbacks
|
||||
mainHandler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
//visibility related code
|
||||
private fun showFolderViewIcons() {
|
||||
binding.folderOrientation.visibility = View.VISIBLE
|
||||
binding.settings.visibility = View.VISIBLE
|
||||
binding.delete.visibility = View.GONE
|
||||
binding.deleteSelected.visibility = View.GONE
|
||||
binding.menuButton.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
binding.edit.visibility = View.GONE
|
||||
// Ensure FABs are properly managed
|
||||
if (currentFolder == null) {
|
||||
|
||||
binding.addFolder.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
private fun showFolderSelectionIcons() {
|
||||
binding.folderOrientation.visibility = View.GONE
|
||||
binding.settings.visibility = View.GONE
|
||||
binding.delete.visibility = View.VISIBLE
|
||||
binding.deleteSelected.visibility = View.VISIBLE
|
||||
binding.menuButton.visibility = View.GONE
|
||||
binding.addFolder.visibility = View.GONE
|
||||
|
||||
// Update edit button visibility based on current selection count
|
||||
updateEditButtonVisibility()
|
||||
}
|
||||
private fun exitFolderSelectionMode() {
|
||||
showFolderViewIcons()
|
||||
}
|
||||
|
||||
private fun handleFolderSelectionModeChange(isSelectionMode: Boolean) {
|
||||
if (!isSelectionMode) {
|
||||
exitFolderSelectionMode()
|
||||
} else {
|
||||
enterFolderSelectionMode()
|
||||
}
|
||||
// Always update edit button visibility when selection mode changes
|
||||
updateEditButtonVisibility()
|
||||
}
|
||||
|
||||
private fun editSelectedFolder() {
|
||||
val selectedFolders = when {
|
||||
folderAdapter != null -> folderAdapter?.getSelectedItems() ?: emptyList()
|
||||
listFolderAdapter != null -> listFolderAdapter?.getSelectedItems() ?: emptyList()
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
if (selectedFolders.size != 1) {
|
||||
Toast.makeText(this, "Please select exactly one folder to edit", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
val folder = selectedFolders[0]
|
||||
showEditFolderDialog(folder)
|
||||
}
|
||||
|
||||
private fun showEditFolderDialog(folder: File) {
|
||||
val inputEditText = EditText(this).apply {
|
||||
setText(folder.name)
|
||||
selectAll()
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle("Rename Folder")
|
||||
.setView(inputEditText)
|
||||
.setPositiveButton("Rename") { dialog, _ ->
|
||||
val newName = inputEditText.text.toString().trim()
|
||||
if (newName.isNotEmpty() && newName != folder.name) {
|
||||
if (isValidFolderName(newName)) {
|
||||
renameFolder(folder, newName)
|
||||
} else {
|
||||
Toast.makeText(this, "Invalid folder name", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun isValidFolderName(folderName: String): Boolean {
|
||||
val forbiddenChars = charArrayOf('/', '\\', ':', '*', '?', '"', '<', '>', '|')
|
||||
return folderName.isNotBlank() &&
|
||||
folderName.none { it in forbiddenChars } &&
|
||||
!folderName.startsWith(".") &&
|
||||
folderName.length <= 255
|
||||
}
|
||||
|
||||
private fun renameFolder(oldFolder: File, newName: String) {
|
||||
val parentDir = oldFolder.parentFile
|
||||
if (parentDir != null) {
|
||||
val newFolder = File(parentDir, newName)
|
||||
if (newFolder.exists()) {
|
||||
Toast.makeText(this, "Folder with this name already exists", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
if (oldFolder.renameTo(newFolder)) {
|
||||
// Clear selection from both adapters
|
||||
folderAdapter?.clearSelection()
|
||||
listFolderAdapter?.clearSelection()
|
||||
|
||||
// Exit selection mode
|
||||
exitFolderSelectionMode()
|
||||
|
||||
refreshCurrentView()
|
||||
} else {
|
||||
Toast.makeText(this, "Failed to rename folder", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package devs.org.calculator.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import devs.org.calculator.databinding.ActivityHiddenVaultBinding
|
||||
import devs.org.calculator.utils.FileManager
|
||||
|
||||
class HiddenVaultActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityHiddenVaultBinding
|
||||
private lateinit var fileManager: FileManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityHiddenVaultBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
fileManager = FileManager(this, this)
|
||||
setupNavigation()
|
||||
}
|
||||
|
||||
private fun setupNavigation() {
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package devs.org.calculator.activities
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
@@ -30,6 +31,7 @@ class PreviewActivity : AppCompatActivity() {
|
||||
binding = ActivityPreviewBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
fileManager = FileManager(this, this)
|
||||
|
||||
currentPosition = intent.getIntExtra("position", 0)
|
||||
@@ -55,6 +57,21 @@ class PreviewActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupFlagSecure()
|
||||
}
|
||||
|
||||
private fun setupFlagSecure() {
|
||||
val prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
||||
if (prefs.getBoolean("screenshot_restriction", true)) {
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_SECURE,
|
||||
WindowManager.LayoutParams.FLAG_SECURE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupFileType() {
|
||||
when (type) {
|
||||
"IMAGE" -> {
|
||||
|
||||
@@ -1,20 +1,154 @@
|
||||
package devs.org.calculator.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import devs.org.calculator.R
|
||||
import devs.org.calculator.databinding.ActivitySettingsBinding
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
private lateinit var prefs: SharedPreferences
|
||||
private val DEV_GITHUB_URL = "https://github.com/binondi"
|
||||
private val GITHUB_URL = "$DEV_GITHUB_URL/calculator-hide-files"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
||||
setupUI()
|
||||
loadSettings()
|
||||
setupListeners()
|
||||
}
|
||||
|
||||
private fun setupUI() {
|
||||
binding.back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadSettings() {
|
||||
|
||||
binding.dynamicThemeSwitch.isChecked = prefs.getBoolean("dynamic_theme", true)
|
||||
|
||||
val themeMode = prefs.getInt("theme_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
binding.themeModeSwitch.isChecked = themeMode != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
|
||||
when (themeMode) {
|
||||
AppCompatDelegate.MODE_NIGHT_YES -> binding.darkThemeRadio.isChecked = true
|
||||
AppCompatDelegate.MODE_NIGHT_NO -> binding.lightThemeRadio.isChecked = true
|
||||
else -> binding.systemThemeRadio.isChecked = true
|
||||
}
|
||||
|
||||
binding.screenshotRestrictionSwitch.isChecked = prefs.getBoolean("screenshot_restriction", true)
|
||||
binding.showFileNames.isChecked = prefs.getBoolean("showFileName", true)
|
||||
|
||||
updateThemeModeVisibility()
|
||||
}
|
||||
|
||||
private fun setupListeners() {
|
||||
|
||||
binding.githubButton.setOnClickListener {
|
||||
openUrl(GITHUB_URL)
|
||||
}
|
||||
|
||||
binding.devGithubButton.setOnClickListener {
|
||||
openUrl(DEV_GITHUB_URL)
|
||||
}
|
||||
|
||||
binding.dynamicThemeSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
prefs.edit().putBoolean("dynamic_theme", isChecked).apply()
|
||||
if (!isChecked) {
|
||||
showThemeModeDialog()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
binding.themeModeSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
binding.themeRadioGroup.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||
if (!isChecked) {
|
||||
binding.systemThemeRadio.isChecked = true
|
||||
applyThemeMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
}
|
||||
}
|
||||
|
||||
binding.themeRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||
val themeMode = when (checkedId) {
|
||||
R.id.lightThemeRadio -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
R.id.darkThemeRadio -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
applyThemeMode(themeMode)
|
||||
}
|
||||
|
||||
binding.screenshotRestrictionSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
prefs.edit().putBoolean("screenshot_restriction", isChecked).apply()
|
||||
if (isChecked) {
|
||||
enableScreenshotRestriction()
|
||||
} else {
|
||||
disableScreenshotRestriction()
|
||||
}
|
||||
}
|
||||
binding.showFileNames.setOnCheckedChangeListener { _, isChecked ->
|
||||
prefs.edit().putBoolean("showFileName", isChecked).apply()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateThemeModeVisibility() {
|
||||
binding.themeRadioGroup.visibility = if (binding.themeModeSwitch.isChecked) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun showThemeModeDialog() {
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle("Theme Mode")
|
||||
.setMessage("Would you like to set a specific theme mode?")
|
||||
.setPositiveButton("Yes") { _, _ ->
|
||||
binding.themeModeSwitch.isChecked = true
|
||||
}
|
||||
.setNegativeButton("No") { _, _ ->
|
||||
binding.systemThemeRadio.isChecked = true
|
||||
applyThemeMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun applyThemeMode(themeMode: Int) {
|
||||
prefs.edit().putInt("theme_mode", themeMode).apply()
|
||||
AppCompatDelegate.setDefaultNightMode(themeMode)
|
||||
}
|
||||
|
||||
private fun enableScreenshotRestriction() {
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_SECURE,
|
||||
WindowManager.LayoutParams.FLAG_SECURE
|
||||
)
|
||||
}
|
||||
|
||||
private fun disableScreenshotRestriction() {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
|
||||
private fun openUrl(url: String) {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Snackbar.make(binding.root, "Could not open URL", Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
package devs.org.calculator.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
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.callbacks.FileProcessCallback
|
||||
import devs.org.calculator.databinding.ActivityViewFolderBinding
|
||||
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 devs.org.calculator.utils.PrefsUtil
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
class ViewFolderActivity : AppCompatActivity() {
|
||||
|
||||
private var isFabOpen = false
|
||||
private lateinit var fabOpen: Animation
|
||||
private lateinit var fabClose: Animation
|
||||
private lateinit var rotateOpen: Animation
|
||||
private lateinit var rotateClose: Animation
|
||||
private lateinit var binding: ActivityViewFolderBinding
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
private lateinit var fileManager: FileManager
|
||||
private lateinit var folderManager: FolderManager
|
||||
private lateinit var dialogUtil: DialogUtil
|
||||
private var fileAdapter: FileAdapter? = null
|
||||
private var currentFolder: File? = null
|
||||
private val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
||||
private lateinit var pickImageLauncher: ActivityResultLauncher<Intent>
|
||||
private lateinit var prefs: SharedPreferences
|
||||
|
||||
private var customDialog: androidx.appcompat.app.AlertDialog? = null
|
||||
|
||||
private var dialogShowTime: Long = 0
|
||||
private val MINIMUM_DIALOG_DURATION = 1700L
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityViewFolderBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setupAnimations()
|
||||
initialize()
|
||||
setupClickListeners()
|
||||
closeFabs()
|
||||
val folder = intent.getStringExtra("folder").toString()
|
||||
currentFolder = File(folder)
|
||||
if (currentFolder != null){
|
||||
openFolder(currentFolder!!)
|
||||
}else {
|
||||
showEmptyState()
|
||||
}
|
||||
|
||||
setupActivityResultLaunchers()
|
||||
}
|
||||
|
||||
private fun initialize() {
|
||||
fileManager = FileManager(this, this)
|
||||
folderManager = FolderManager(this)
|
||||
dialogUtil = DialogUtil(this)
|
||||
prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
||||
}
|
||||
|
||||
private fun setupActivityResultLaunchers() {
|
||||
pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
handleFilePickerResult(result.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFilePickerResult(data: Intent?) {
|
||||
val clipData = 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 {
|
||||
data?.data?.let { uriList.add(it) }
|
||||
}
|
||||
|
||||
if (uriList.isNotEmpty()) {
|
||||
processSelectedFiles(uriList)
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.no_files_selected), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showCustomDialog(count: Int) {
|
||||
val dialogView = ProccessingDialogBinding.inflate(layoutInflater)
|
||||
customDialog = MaterialAlertDialogBuilder(this)
|
||||
.setView(dialogView.root)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
dialogView.title.text = "Hiding $count 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
|
||||
mainHandler.postDelayed({
|
||||
customDialog?.dismiss()
|
||||
customDialog = null
|
||||
}, remainingTime)
|
||||
} else {
|
||||
customDialog?.dismiss()
|
||||
customDialog = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun processSelectedFiles(uriList: List<Uri>) {
|
||||
val targetFolder = currentFolder ?: hiddenDir
|
||||
|
||||
showCustomDialog(uriList.size)
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
fileManager.processMultipleFiles(uriList, targetFolder,
|
||||
object : FileProcessCallback {
|
||||
override fun onFilesProcessedSuccessfully(copiedFiles: List<File>) {
|
||||
mainHandler.post {
|
||||
refreshCurrentView()
|
||||
dismissCustomDialog()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFileProcessFailed() {
|
||||
mainHandler.post {
|
||||
Toast.makeText(
|
||||
this@ViewFolderActivity,
|
||||
getString(R.string.failed_to_hide_files),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
dismissCustomDialog()
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
mainHandler.post {
|
||||
Toast.makeText(
|
||||
this@ViewFolderActivity,
|
||||
getString(R.string.there_was_a_problem_in_the_folder),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
dismissCustomDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshCurrentView() {
|
||||
if (currentFolder != null) {
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
private fun openFolder(folder: File) {
|
||||
|
||||
val files = folderManager.getFilesInFolder(folder)
|
||||
binding.folderName.text = folder.name
|
||||
|
||||
if (files.isNotEmpty()) {
|
||||
showFileList(files, folder)
|
||||
} else {
|
||||
showEmptyState()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEmptyState() {
|
||||
binding.noItems.visibility = View.VISIBLE
|
||||
binding.recyclerView.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun showFileList(files: List<File>, folder: File) {
|
||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
|
||||
|
||||
// Clean up previous adapter
|
||||
fileAdapter?.cleanup()
|
||||
|
||||
fileAdapter = FileAdapter(this, this, folder, prefs.getBoolean("showFileName", true),
|
||||
onFolderLongClick = { isSelected ->
|
||||
handleFileSelectionModeChange(isSelected, 0)
|
||||
}).apply {
|
||||
setFileOperationCallback(object : FileAdapter.FileOperationCallback {
|
||||
override fun onFileDeleted(file: File) {
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
override fun onFileRenamed(oldFile: File, newFile: File) {
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
override fun onRefreshNeeded() {
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
override fun onSelectionModeChanged(isSelectionMode: Boolean, selectedCount: Int) {
|
||||
handleFileSelectionModeChange(isSelectionMode, selectedCount)
|
||||
}
|
||||
|
||||
override fun onSelectionCountChanged(selectedCount: Int) {
|
||||
updateSelectionCountDisplay(selectedCount)
|
||||
}
|
||||
})
|
||||
|
||||
submitList(files)
|
||||
}
|
||||
|
||||
binding.recyclerView.adapter = fileAdapter
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
binding.noItems.visibility = View.GONE
|
||||
|
||||
// Setup menu button click listener
|
||||
binding.menuButton.setOnClickListener {
|
||||
fileAdapter?.let { adapter ->
|
||||
showFileOptionsMenu(adapter.getSelectedItems())
|
||||
}
|
||||
}
|
||||
|
||||
// Set initial UI state
|
||||
showFileViewIcons()
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("MissingSuperCall")
|
||||
override fun onBackPressed() {
|
||||
handleBackPress()
|
||||
}
|
||||
|
||||
private fun handleBackPress() {
|
||||
if (fileAdapter?.onBackPressed() == true) {
|
||||
return
|
||||
}
|
||||
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
private fun handleFileSelectionModeChange(isSelectionMode: Boolean, selectedCount: Int) {
|
||||
if (isSelectionMode) {
|
||||
showFileSelectionIcons()
|
||||
} else {
|
||||
showFileViewIcons()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSelectionCountDisplay(selectedCount: Int) {
|
||||
// Update any UI elements that show selection count
|
||||
if (selectedCount > 0) {
|
||||
showFileSelectionIcons()
|
||||
} else {
|
||||
showFileViewIcons()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFileOptionsMenu(selectedFiles: List<File>) {
|
||||
if (selectedFiles.isEmpty()) return
|
||||
|
||||
val options = arrayOf(
|
||||
getString(R.string.un_hide),
|
||||
getString(R.string.delete),
|
||||
getString(R.string.copy_to_another_folder),
|
||||
getString(R.string.move_to_another_folder)
|
||||
)
|
||||
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.file_options))
|
||||
.setItems(options) { _, which ->
|
||||
when (which) {
|
||||
0 -> unhideSelectedFiles(selectedFiles)
|
||||
1 -> deleteSelectedFiles(selectedFiles)
|
||||
2 -> copyToAnotherFolder(selectedFiles)
|
||||
3 -> moveToAnotherFolder(selectedFiles)
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun moveToAnotherFolder(selectedFiles: List<File>) {
|
||||
showFolderSelectionDialog { destinationFolder ->
|
||||
moveFilesToFolder(selectedFiles, destinationFolder)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun unhideSelectedFiles(selectedFiles: List<File>) {
|
||||
dialogUtil.showMaterialDialog(
|
||||
getString(R.string.un_hide_files),
|
||||
getString(R.string.are_you_sure_you_want_to_un_hide_selected_files),
|
||||
getString(R.string.un_hide),
|
||||
getString(R.string.cancel),
|
||||
object : DialogUtil.DialogCallback {
|
||||
override fun onPositiveButtonClicked() {
|
||||
performFileUnhiding(selectedFiles)
|
||||
}
|
||||
|
||||
override fun onNegativeButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun onNaturalButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun deleteSelectedFiles(selectedFiles: List<File>) {
|
||||
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() {
|
||||
performFileDeletion(selectedFiles)
|
||||
}
|
||||
|
||||
override fun onNegativeButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun onNaturalButtonClicked() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun refreshCurrentFolder() {
|
||||
currentFolder?.let { folder ->
|
||||
val files = folderManager.getFilesInFolder(folder)
|
||||
fileAdapter?.submitList(files)
|
||||
|
||||
if (files.isEmpty()) {
|
||||
showEmptyState()
|
||||
} else {
|
||||
binding.recyclerView.visibility = View.VISIBLE
|
||||
binding.noItems.visibility = View.GONE
|
||||
fileAdapter?.let { adapter ->
|
||||
if (adapter.isInSelectionMode()) {
|
||||
showFileSelectionIcons()
|
||||
} else {
|
||||
showFileViewIcons()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun setupClickListeners() {
|
||||
binding.fabExpend.setOnClickListener {
|
||||
if (isFabOpen) closeFabs()
|
||||
else openFabs()
|
||||
}
|
||||
binding.back.setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
|
||||
binding.addImage.setOnClickListener { openFilePicker("image/*") }
|
||||
binding.addVideo.setOnClickListener { openFilePicker("video/*") }
|
||||
binding.addAudio.setOnClickListener { openFilePicker("audio/*") }
|
||||
binding.addDocument.setOnClickListener { openFilePicker("*/*") }
|
||||
}
|
||||
|
||||
private fun setupAnimations() {
|
||||
fabOpen = AnimationUtils.loadAnimation(this, R.anim.fab_open)
|
||||
fabClose = AnimationUtils.loadAnimation(this, R.anim.fab_close)
|
||||
rotateOpen = AnimationUtils.loadAnimation(this, R.anim.rotate_open)
|
||||
rotateClose = AnimationUtils.loadAnimation(this, R.anim.rotate_close)
|
||||
}
|
||||
|
||||
private fun openFilePicker(mimeType: String) {
|
||||
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)
|
||||
}
|
||||
pickImageLauncher.launch(intent)
|
||||
}
|
||||
|
||||
private fun openFabs() {
|
||||
if (!isFabOpen) {
|
||||
binding.addImage.startAnimation(fabOpen)
|
||||
binding.addVideo.startAnimation(fabOpen)
|
||||
binding.addAudio.startAnimation(fabOpen)
|
||||
binding.addDocument.startAnimation(fabOpen)
|
||||
binding.fabExpend.startAnimation(rotateOpen)
|
||||
|
||||
binding.addImage.visibility = View.VISIBLE
|
||||
binding.addVideo.visibility = View.VISIBLE
|
||||
binding.addAudio.visibility = View.VISIBLE
|
||||
binding.addDocument.visibility = View.VISIBLE
|
||||
|
||||
isFabOpen = true
|
||||
mainHandler.postDelayed({
|
||||
binding.fabExpend.setImageResource(R.drawable.wrong)
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
|
||||
private fun closeFabs() {
|
||||
if (isFabOpen) {
|
||||
binding.addImage.startAnimation(fabClose)
|
||||
binding.addVideo.startAnimation(fabClose)
|
||||
binding.addAudio.startAnimation(fabClose)
|
||||
binding.addDocument.startAnimation(fabClose)
|
||||
binding.fabExpend.startAnimation(rotateClose)
|
||||
|
||||
binding.addImage.visibility = View.INVISIBLE
|
||||
binding.addVideo.visibility = View.INVISIBLE
|
||||
binding.addAudio.visibility = View.INVISIBLE
|
||||
binding.addDocument.visibility = View.INVISIBLE
|
||||
|
||||
isFabOpen = false
|
||||
binding.fabExpend.setImageResource(R.drawable.ic_add)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFileViewIcons() {
|
||||
binding.menuButton.visibility = View.GONE
|
||||
binding.fabExpend.visibility = View.VISIBLE
|
||||
binding.addImage.visibility = View.INVISIBLE
|
||||
binding.addVideo.visibility = View.INVISIBLE
|
||||
binding.addAudio.visibility = View.INVISIBLE
|
||||
binding.addDocument.visibility = View.INVISIBLE
|
||||
isFabOpen = false
|
||||
binding.fabExpend.setImageResource(R.drawable.ic_add)
|
||||
}
|
||||
|
||||
private fun showFileSelectionIcons() {
|
||||
binding.menuButton.visibility = View.VISIBLE
|
||||
binding.fabExpend.visibility = View.GONE
|
||||
binding.addImage.visibility = View.INVISIBLE
|
||||
binding.addVideo.visibility = View.INVISIBLE
|
||||
binding.addAudio.visibility = View.INVISIBLE
|
||||
binding.addDocument.visibility = View.INVISIBLE
|
||||
isFabOpen = false
|
||||
}
|
||||
|
||||
private fun performFileUnhiding(selectedFiles: List<File>) {
|
||||
lifecycleScope.launch {
|
||||
var allUnhidden = true
|
||||
selectedFiles.forEach { file ->
|
||||
try {
|
||||
val fileUri = Uri.fromFile(file)
|
||||
val result = fileManager.copyFileToNormalDir(fileUri)
|
||||
if (result == null) {
|
||||
allUnhidden = false
|
||||
} else {
|
||||
// Delete the hidden file after successful copy
|
||||
file.delete()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
allUnhidden = false
|
||||
}
|
||||
}
|
||||
|
||||
mainHandler.post {
|
||||
val message = if (allUnhidden) {
|
||||
getString(R.string.files_unhidden_successfully)
|
||||
} else {
|
||||
getString(R.string.some_files_could_not_be_unhidden)
|
||||
}
|
||||
|
||||
Toast.makeText(this@ViewFolderActivity, message, Toast.LENGTH_SHORT).show()
|
||||
|
||||
// Fixed: Ensure proper order of operations
|
||||
fileAdapter?.exitSelectionMode()
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun performFileDeletion(selectedFiles: List<File>) {
|
||||
var allDeleted = true
|
||||
selectedFiles.forEach { file ->
|
||||
if (!file.delete()) {
|
||||
allDeleted = false
|
||||
}
|
||||
}
|
||||
|
||||
val message = if (allDeleted) {
|
||||
getString(R.string.files_deleted_successfully)
|
||||
} else {
|
||||
getString(R.string.some_items_could_not_be_deleted)
|
||||
}
|
||||
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
|
||||
// Fixed: Ensure proper order of operations
|
||||
fileAdapter?.exitSelectionMode()
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
private fun copyToAnotherFolder(selectedFiles: List<File>) {
|
||||
showFolderSelectionDialog { destinationFolder ->
|
||||
copyFilesToFolder(selectedFiles, destinationFolder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyFilesToFolder(selectedFiles: List<File>, destinationFolder: File) {
|
||||
var allCopied = true
|
||||
selectedFiles.forEach { file ->
|
||||
try {
|
||||
val newFile = File(destinationFolder, file.name)
|
||||
file.copyTo(newFile, overwrite = true)
|
||||
} catch (e: Exception) {
|
||||
allCopied = false
|
||||
}
|
||||
}
|
||||
|
||||
val message = if (allCopied) "Files copied successfully" else "Some files could not be copied"
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
|
||||
// Fixed: Ensure proper order of operations
|
||||
fileAdapter?.exitSelectionMode()
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
private fun moveFilesToFolder(selectedFiles: List<File>, destinationFolder: File) {
|
||||
var allMoved = true
|
||||
selectedFiles.forEach { file ->
|
||||
try {
|
||||
val newFile = File(destinationFolder, file.name)
|
||||
file.copyTo(newFile, overwrite = true)
|
||||
file.delete()
|
||||
} catch (e: Exception) {
|
||||
allMoved = false
|
||||
}
|
||||
}
|
||||
|
||||
val message = if (allMoved) "Files moved successfully" else "Some files could not be moved"
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
|
||||
// Fixed: Ensure proper order of operations
|
||||
fileAdapter?.exitSelectionMode()
|
||||
refreshCurrentFolder()
|
||||
}
|
||||
|
||||
private fun showFolderSelectionDialog(onFolderSelected: (File) -> Unit) {
|
||||
val folders = folderManager.getFoldersInDirectory(hiddenDir)
|
||||
.filter { it != currentFolder } // Exclude current folder
|
||||
|
||||
if (folders.isEmpty()) {
|
||||
Toast.makeText(this, getString(R.string.no_folders_available), Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
val folderNames = folders.map { it.name }.toTypedArray()
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.select_destination_folder))
|
||||
.setItems(folderNames) { _, which ->
|
||||
onFolderSelected(folders[which])
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package devs.org.calculator.adapters
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -16,21 +17,37 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import devs.org.calculator.R
|
||||
import devs.org.calculator.activities.PreviewActivity
|
||||
import devs.org.calculator.utils.FileManager
|
||||
import java.io.File
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class FileAdapter(
|
||||
private val context: Context,
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
private val currentFolder: File
|
||||
private val currentFolder: File,
|
||||
private val showFileName: Boolean,
|
||||
private val onFolderLongClick: (Boolean) -> Unit
|
||||
) : ListAdapter<File, FileAdapter.FileViewHolder>(FileDiffCallback()) {
|
||||
|
||||
private val selectedItems = mutableSetOf<Int>()
|
||||
private var isSelectionMode = false
|
||||
|
||||
// Use WeakReference to prevent memory leaks
|
||||
private var fileOperationCallback: WeakReference<FileOperationCallback>? = null
|
||||
|
||||
// Background executor for file operations
|
||||
private val fileExecutor = Executors.newSingleThreadExecutor()
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
companion object {
|
||||
private const val TAG = "FileAdapter"
|
||||
}
|
||||
|
||||
// Callback interface for handling file operations and selection changes
|
||||
interface FileOperationCallback {
|
||||
fun onFileDeleted(file: File)
|
||||
@@ -40,23 +57,29 @@ class FileAdapter(
|
||||
fun onSelectionCountChanged(selectedCount: Int)
|
||||
}
|
||||
|
||||
var fileOperationCallback: FileOperationCallback? = null
|
||||
fun setFileOperationCallback(callback: FileOperationCallback?) {
|
||||
fileOperationCallback = callback?.let { WeakReference(it) }
|
||||
}
|
||||
|
||||
inner class FileViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val imageView: ImageView = view.findViewById(R.id.fileIconImageView)
|
||||
val fileNameTextView: TextView = view.findViewById(R.id.fileNameTextView)
|
||||
val playIcon: ImageView = view.findViewById(R.id.videoPlay)
|
||||
val selectionOverlay: View? = view.findViewById(R.id.selectedLayer) // Optional overlay for selection
|
||||
val checkIcon: ImageView? = view.findViewById(R.id.selected) // Optional check icon
|
||||
val selectedLayer: View = view.findViewById(R.id.selectedLayer)
|
||||
val selected: ImageView = view.findViewById(R.id.selected)
|
||||
|
||||
fun bind(file: File) {
|
||||
val fileType = FileManager(context, lifecycleOwner).getFileType(file)
|
||||
setupFileDisplay(file, fileType)
|
||||
setupClickListeners(file, fileType)
|
||||
fileNameTextView.visibility = if (showFileName) View.VISIBLE else View.GONE
|
||||
|
||||
// Handle selection state
|
||||
val isSelected = selectedItems.contains(adapterPosition)
|
||||
updateSelectionUI(isSelected)
|
||||
// Update selection state
|
||||
val position = adapterPosition
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
val isSelected = selectedItems.contains(position)
|
||||
updateSelectionUI(isSelected)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(file: File, payloads: List<Any>) {
|
||||
@@ -76,101 +99,88 @@ class FileAdapter(
|
||||
// Could update file info if displayed
|
||||
}
|
||||
"SELECTION_CHANGED" -> {
|
||||
val isSelected = selectedItems.contains(adapterPosition)
|
||||
updateSelectionUI(isSelected)
|
||||
val position = adapterPosition
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
val isSelected = selectedItems.contains(position)
|
||||
updateSelectionUI(isSelected)
|
||||
// Notify activity about selection change
|
||||
notifySelectionModeChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSelectionUI(isSelected: Boolean) {
|
||||
// Update visual selection state
|
||||
itemView.isSelected = isSelected
|
||||
|
||||
// If you have a selection overlay, show/hide it
|
||||
selectionOverlay?.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
|
||||
// If you have a check icon, show/hide it
|
||||
checkIcon?.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
|
||||
// You can also change the background or add other visual indicators
|
||||
itemView.alpha = if (isSelectionMode && !isSelected) 0.7f else 1.0f
|
||||
selectedLayer.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
selected.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
private fun setupFileDisplay(file: File, fileType: FileManager.FileType) {
|
||||
fileNameTextView.text = file.name
|
||||
|
||||
when (fileType) {
|
||||
FileManager.FileType.IMAGE -> {
|
||||
loadImageThumbnail(file)
|
||||
fileNameTextView.visibility = View.GONE
|
||||
playIcon.visibility = View.GONE
|
||||
Glide.with(context)
|
||||
.load(file)
|
||||
.centerCrop()
|
||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||
.error(R.drawable.ic_document)
|
||||
.placeholder(R.drawable.ic_document)
|
||||
.into(imageView)
|
||||
}
|
||||
FileManager.FileType.VIDEO -> {
|
||||
loadVideoThumbnail(file)
|
||||
fileNameTextView.visibility = View.GONE
|
||||
playIcon.visibility = View.VISIBLE
|
||||
Glide.with(context)
|
||||
.load(file)
|
||||
.centerCrop()
|
||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||
.error(R.drawable.ic_document)
|
||||
.placeholder(R.drawable.ic_document)
|
||||
.into(imageView)
|
||||
}
|
||||
FileManager.FileType.AUDIO -> {
|
||||
playIcon.visibility = View.GONE
|
||||
imageView.setImageResource(R.drawable.ic_audio)
|
||||
}
|
||||
else -> {
|
||||
loadFileIcon(fileType)
|
||||
fileNameTextView.visibility = View.VISIBLE
|
||||
playIcon.visibility = View.GONE
|
||||
imageView.setImageResource(R.drawable.ic_document)
|
||||
}
|
||||
}
|
||||
fileNameTextView.text = file.name
|
||||
}
|
||||
|
||||
private fun loadImageThumbnail(file: File) {
|
||||
Glide.with(imageView)
|
||||
.load(file)
|
||||
.thumbnail(0.1f)
|
||||
.centerCrop()
|
||||
.override(300, 300)
|
||||
.placeholder(R.drawable.ic_file)
|
||||
.error(R.drawable.ic_file)
|
||||
.into(imageView)
|
||||
}
|
||||
|
||||
private fun loadVideoThumbnail(file: File) {
|
||||
Glide.with(imageView)
|
||||
.asBitmap()
|
||||
.load(file)
|
||||
.thumbnail(0.1f)
|
||||
.centerCrop()
|
||||
.override(300, 300)
|
||||
.placeholder(R.drawable.ic_file)
|
||||
.error(R.drawable.ic_file)
|
||||
.into(imageView)
|
||||
}
|
||||
|
||||
private fun loadFileIcon(fileType: FileManager.FileType) {
|
||||
val resourceId = when (fileType) {
|
||||
FileManager.FileType.AUDIO -> R.drawable.ic_audio
|
||||
FileManager.FileType.DOCUMENT -> R.drawable.ic_document
|
||||
else -> R.drawable.ic_file
|
||||
}
|
||||
imageView.setImageResource(resourceId)
|
||||
}
|
||||
|
||||
private fun setupClickListeners(file: File, fileType: FileManager.FileType) {
|
||||
itemView.setOnClickListener {
|
||||
val position = adapterPosition
|
||||
if (position == RecyclerView.NO_POSITION) return@setOnClickListener
|
||||
|
||||
if (isSelectionMode) {
|
||||
toggleSelection(adapterPosition)
|
||||
return@setOnClickListener
|
||||
toggleSelection(position)
|
||||
} else {
|
||||
openFile(file, fileType)
|
||||
}
|
||||
openFile(file, fileType)
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
val position = adapterPosition
|
||||
if (position == RecyclerView.NO_POSITION) return@setOnLongClickListener false
|
||||
|
||||
if (!isSelectionMode) {
|
||||
showFileOptionsDialog(file)
|
||||
true
|
||||
} else {
|
||||
toggleSelection(adapterPosition)
|
||||
true
|
||||
enterSelectionMode()
|
||||
toggleSelection(position)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFile(file: File, fileType: FileManager.FileType) {
|
||||
if (!file.exists()) {
|
||||
Toast.makeText(context, "File no longer exists", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
when (fileType) {
|
||||
FileManager.FileType.AUDIO -> openAudioFile(file)
|
||||
FileManager.FileType.IMAGE, FileManager.FileType.VIDEO -> openInPreview(fileType)
|
||||
@@ -180,19 +190,20 @@ class FileAdapter(
|
||||
}
|
||||
|
||||
private fun openAudioFile(file: File) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(uri, "audio/*")
|
||||
putExtra("folder", currentFolder.toString())
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
try {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(uri, "audio/*")
|
||||
putExtra("folder", currentFolder.toString())
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to open audio file: ${e.message}")
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.no_audio_player_found),
|
||||
@@ -202,19 +213,20 @@ class FileAdapter(
|
||||
}
|
||||
|
||||
private fun openDocumentFile(file: File) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(uri, "*/*")
|
||||
putExtra("folder", currentFolder.toString())
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
try {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(uri, "*/*")
|
||||
putExtra("folder", currentFolder.toString())
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to open document file: ${e.message}")
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.no_suitable_app_found_to_open_this_document),
|
||||
@@ -239,23 +251,41 @@ class FileAdapter(
|
||||
}
|
||||
|
||||
private fun showFileOptionsDialog(file: File) {
|
||||
val options = arrayOf(
|
||||
context.getString(R.string.un_hide),
|
||||
context.getString(R.string.select_multiple),
|
||||
context.getString(R.string.rename),
|
||||
context.getString(R.string.delete),
|
||||
context.getString(R.string.share)
|
||||
)
|
||||
val options = if (isSelectionMode) {
|
||||
arrayOf(
|
||||
context.getString(R.string.un_hide),
|
||||
context.getString(R.string.delete),
|
||||
context.getString(R.string.copy_to_another_folder),
|
||||
context.getString(R.string.move_to_another_folder)
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
context.getString(R.string.un_hide),
|
||||
context.getString(R.string.select_multiple),
|
||||
context.getString(R.string.rename),
|
||||
context.getString(R.string.delete),
|
||||
context.getString(R.string.share)
|
||||
)
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(context.getString(R.string.file_options))
|
||||
.setItems(options) { dialog, which ->
|
||||
when (which) {
|
||||
0 -> unHideFile(file)
|
||||
1 -> enableSelectMultipleFiles()
|
||||
2 -> renameFile(file)
|
||||
3 -> deleteFile(file)
|
||||
4 -> shareFile(file)
|
||||
if (isSelectionMode) {
|
||||
when (which) {
|
||||
0 -> unHideFile(file)
|
||||
1 -> deleteFile(file)
|
||||
2 -> copyToAnotherFolder(file)
|
||||
3 -> moveToAnotherFolder(file)
|
||||
}
|
||||
} else {
|
||||
when (which) {
|
||||
0 -> unHideFile(file)
|
||||
1 -> enableSelectMultipleFiles()
|
||||
2 -> renameFile(file)
|
||||
3 -> deleteFile(file)
|
||||
4 -> shareFile(file)
|
||||
}
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
@@ -264,18 +294,19 @@ class FileAdapter(
|
||||
}
|
||||
|
||||
private fun enableSelectMultipleFiles() {
|
||||
// Enable multiple selection mode and select current item
|
||||
val position = adapterPosition
|
||||
if (position == RecyclerView.NO_POSITION) return
|
||||
|
||||
enterSelectionMode()
|
||||
selectedItems.add(adapterPosition)
|
||||
notifyItemChanged(adapterPosition, listOf("SELECTION_CHANGED"))
|
||||
fileOperationCallback?.onSelectionCountChanged(selectedItems.size)
|
||||
selectedItems.add(position)
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
}
|
||||
|
||||
private fun unHideFile(file: File) {
|
||||
FileManager(context, lifecycleOwner).unHideFile(
|
||||
file = file,
|
||||
onSuccess = {
|
||||
fileOperationCallback?.onFileDeleted(file)
|
||||
fileOperationCallback?.get()?.onFileDeleted(file)
|
||||
},
|
||||
onError = { errorMessage ->
|
||||
Toast.makeText(context, "Failed to unhide: $errorMessage", Toast.LENGTH_SHORT).show()
|
||||
@@ -284,11 +315,34 @@ class FileAdapter(
|
||||
}
|
||||
|
||||
private fun deleteFile(file: File) {
|
||||
if (file.delete()) {
|
||||
fileOperationCallback?.onFileDeleted(file)
|
||||
Toast.makeText(context, "File deleted", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(context, "Failed to delete file", Toast.LENGTH_SHORT).show()
|
||||
// Show confirmation dialog first
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle("Delete File")
|
||||
.setMessage("Are you sure you want to delete ${file.name}?")
|
||||
.setPositiveButton("Delete") { _, _ ->
|
||||
deleteFileAsync(file)
|
||||
}
|
||||
.setNegativeButton("Cancel", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun deleteFileAsync(file: File) {
|
||||
fileExecutor.execute {
|
||||
val success = try {
|
||||
file.delete()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to delete file: ${e.message}")
|
||||
false
|
||||
}
|
||||
|
||||
mainHandler.post {
|
||||
if (success) {
|
||||
fileOperationCallback?.get()?.onFileDeleted(file)
|
||||
Toast.makeText(context, "File deleted", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(context, "Failed to delete file", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,15 +358,10 @@ class FileAdapter(
|
||||
.setPositiveButton(context.getString(R.string.rename)) { dialog, _ ->
|
||||
val newName = inputEditText.text.toString().trim()
|
||||
if (newName.isNotEmpty() && newName != file.name) {
|
||||
val parentDir = file.parentFile
|
||||
if (parentDir != null) {
|
||||
val newFile = File(parentDir, newName)
|
||||
if (file.renameTo(newFile)) {
|
||||
fileOperationCallback?.onFileRenamed(file, newFile)
|
||||
Toast.makeText(context, "File renamed", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(context, "Failed to rename file", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
if (isValidFileName(newName)) {
|
||||
renameFileAsync(file, newName)
|
||||
} else {
|
||||
Toast.makeText(context, "Invalid file name", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
dialog.dismiss()
|
||||
@@ -324,37 +373,87 @@ class FileAdapter(
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun shareFile(file: File) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = context.contentResolver.getType(uri) ?: "*/*"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
private fun isValidFileName(fileName: String): Boolean {
|
||||
val forbiddenChars = charArrayOf('/', '\\', ':', '*', '?', '"', '<', '>', '|')
|
||||
return fileName.isNotBlank() &&
|
||||
fileName.none { it in forbiddenChars } &&
|
||||
!fileName.startsWith(".") &&
|
||||
fileName.length <= 255
|
||||
}
|
||||
|
||||
private fun renameFileAsync(file: File, newName: String) {
|
||||
fileExecutor.execute {
|
||||
val parentDir = file.parentFile
|
||||
if (parentDir != null) {
|
||||
val newFile = File(parentDir, newName)
|
||||
if (newFile.exists()) {
|
||||
mainHandler.post {
|
||||
Toast.makeText(context, "File with this name already exists", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
return@execute
|
||||
}
|
||||
|
||||
val success = try {
|
||||
file.renameTo(newFile)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to rename file: ${e.message}")
|
||||
false
|
||||
}
|
||||
|
||||
mainHandler.post {
|
||||
if (success) {
|
||||
fileOperationCallback?.get()?.onFileRenamed(file, newFile)
|
||||
Toast.makeText(context, "File renamed", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(context, "Failed to rename file", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(shareIntent, context.getString(R.string.share_file))
|
||||
)
|
||||
}
|
||||
|
||||
private fun shareFile(file: File) {
|
||||
try {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = context.contentResolver.getType(uri) ?: "*/*"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(shareIntent, context.getString(R.string.share_file))
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to share file: ${e.message}")
|
||||
Toast.makeText(context, "Failed to share file", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyToAnotherFolder(file: File) {
|
||||
// This will be handled by the activity
|
||||
fileOperationCallback?.get()?.onRefreshNeeded()
|
||||
}
|
||||
|
||||
private fun moveToAnotherFolder(file: File) {
|
||||
// This will be handled by the activity
|
||||
fileOperationCallback?.get()?.onRefreshNeeded()
|
||||
}
|
||||
|
||||
private fun toggleSelection(position: Int) {
|
||||
if (selectedItems.contains(position)) {
|
||||
selectedItems.remove(position)
|
||||
if (selectedItems.isEmpty()) {
|
||||
exitSelectionMode()
|
||||
}
|
||||
} else {
|
||||
selectedItems.add(position)
|
||||
}
|
||||
|
||||
// Exit selection mode if no items are selected
|
||||
if (selectedItems.isEmpty()) {
|
||||
exitSelectionMode()
|
||||
} else {
|
||||
fileOperationCallback?.onSelectionCountChanged(selectedItems.size)
|
||||
}
|
||||
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
onSelectionCountChanged(selectedItems.size)
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,29 +464,30 @@ class FileAdapter(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: FileViewHolder, position: Int) {
|
||||
val file = getItem(position)
|
||||
holder.bind(file)
|
||||
if (position < itemCount) {
|
||||
val file = getItem(position)
|
||||
holder.bind(file)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: FileViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
if (payloads.isEmpty()) {
|
||||
super.onBindViewHolder(holder, position, payloads)
|
||||
} else {
|
||||
val file = getItem(position)
|
||||
holder.bind(file, payloads)
|
||||
if (position < itemCount) {
|
||||
val file = getItem(position)
|
||||
holder.bind(file, payloads)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public methods for external control
|
||||
|
||||
/**
|
||||
* Enter selection mode
|
||||
* Enter selection mode and notify callback immediately
|
||||
*/
|
||||
fun enterSelectionMode() {
|
||||
if (!isSelectionMode) {
|
||||
isSelectionMode = true
|
||||
fileOperationCallback?.onSelectionModeChanged(true, selectedItems.size)
|
||||
notifyDataSetChanged() // Refresh all items to show selection UI
|
||||
notifySelectionModeChange()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,8 +498,8 @@ class FileAdapter(
|
||||
if (isSelectionMode) {
|
||||
isSelectionMode = false
|
||||
selectedItems.clear()
|
||||
fileOperationCallback?.onSelectionModeChanged(false, 0)
|
||||
notifyDataSetChanged() // Refresh all items to hide selection UI
|
||||
notifySelectionModeChange()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,11 +510,11 @@ class FileAdapter(
|
||||
if (selectedItems.isNotEmpty()) {
|
||||
val previouslySelected = selectedItems.toSet()
|
||||
selectedItems.clear()
|
||||
fileOperationCallback?.onSelectionCountChanged(0)
|
||||
|
||||
// Only update previously selected items
|
||||
fileOperationCallback?.get()?.onSelectionCountChanged(0)
|
||||
previouslySelected.forEach { position ->
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
if (position < itemCount) {
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,16 +535,33 @@ class FileAdapter(
|
||||
selectedItems.add(i)
|
||||
}
|
||||
|
||||
fileOperationCallback?.onSelectionCountChanged(selectedItems.size)
|
||||
// Notify callback about selection change
|
||||
fileOperationCallback?.get()?.onSelectionCountChanged(selectedItems.size)
|
||||
|
||||
// Update UI for changed items
|
||||
val allPositions = (0 until itemCount).toSet()
|
||||
val changedPositions = allPositions - previouslySelected + previouslySelected - allPositions
|
||||
changedPositions.forEach { position ->
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
// Update UI for changed items efficiently
|
||||
updateSelectionItems(selectedItems.toSet(), previouslySelected)
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently update selection UI for changed items only
|
||||
*/
|
||||
private fun updateSelectionItems(newSelections: Set<Int>, oldSelections: Set<Int>) {
|
||||
val changedItems = (oldSelections - newSelections) + (newSelections - oldSelections)
|
||||
changedItems.forEach { position ->
|
||||
if (position < itemCount) {
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized method to notify selection mode changes
|
||||
*/
|
||||
private fun notifySelectionModeChange() {
|
||||
fileOperationCallback?.get()?.onSelectionModeChanged(isSelectionMode, selectedItems.size)
|
||||
onFolderLongClick(isSelectionMode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected files
|
||||
*/
|
||||
@@ -465,34 +582,67 @@ class FileAdapter(
|
||||
fun isInSelectionMode(): Boolean = isSelectionMode
|
||||
|
||||
/**
|
||||
* Delete selected files
|
||||
* Delete selected files with proper error handling and background processing
|
||||
*/
|
||||
fun deleteSelectedFiles() {
|
||||
val selectedFiles = getSelectedItems()
|
||||
var deletedCount = 0
|
||||
var failedCount = 0
|
||||
if (selectedFiles.isEmpty()) return
|
||||
|
||||
selectedFiles.forEach { file ->
|
||||
if (file.delete()) {
|
||||
deletedCount++
|
||||
fileOperationCallback?.onFileDeleted(file)
|
||||
} else {
|
||||
failedCount++
|
||||
// Show confirmation dialog
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle("Delete Files")
|
||||
.setMessage("Are you sure you want to delete ${selectedFiles.size} file(s)?")
|
||||
.setPositiveButton("Delete") { _, _ ->
|
||||
deleteFilesAsync(selectedFiles)
|
||||
}
|
||||
}
|
||||
.setNegativeButton("Cancel", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
exitSelectionMode()
|
||||
private fun deleteFilesAsync(selectedFiles: List<File>) {
|
||||
fileExecutor.execute {
|
||||
var deletedCount = 0
|
||||
var failedCount = 0
|
||||
val failedFiles = mutableListOf<String>()
|
||||
|
||||
// Show result message
|
||||
when {
|
||||
deletedCount > 0 && failedCount == 0 -> {
|
||||
Toast.makeText(context, "Deleted $deletedCount file(s)", Toast.LENGTH_SHORT).show()
|
||||
selectedFiles.forEach { file ->
|
||||
try {
|
||||
if (file.delete()) {
|
||||
deletedCount++
|
||||
mainHandler.post {
|
||||
fileOperationCallback?.get()?.onFileDeleted(file)
|
||||
}
|
||||
} else {
|
||||
failedCount++
|
||||
failedFiles.add(file.name)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
failedCount++
|
||||
failedFiles.add(file.name)
|
||||
Log.e(TAG, "Failed to delete ${file.name}: ${e.message}")
|
||||
}
|
||||
}
|
||||
deletedCount > 0 && failedCount > 0 -> {
|
||||
Toast.makeText(context, "Deleted $deletedCount file(s), failed to delete $failedCount", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
failedCount > 0 -> {
|
||||
Toast.makeText(context, "Failed to delete $failedCount file(s)", Toast.LENGTH_SHORT).show()
|
||||
|
||||
mainHandler.post {
|
||||
// Exit selection mode first
|
||||
exitSelectionMode()
|
||||
|
||||
// Show detailed result message
|
||||
when {
|
||||
deletedCount > 0 && failedCount == 0 -> {
|
||||
Toast.makeText(context, "Deleted $deletedCount file(s)", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
deletedCount > 0 && failedCount > 0 -> {
|
||||
Toast.makeText(context,
|
||||
"Deleted $deletedCount file(s), failed to delete $failedCount",
|
||||
Toast.LENGTH_LONG).show()
|
||||
}
|
||||
failedCount > 0 -> {
|
||||
Toast.makeText(context,
|
||||
"Failed to delete $failedCount file(s)",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,39 +654,54 @@ class FileAdapter(
|
||||
val selectedFiles = getSelectedItems()
|
||||
if (selectedFiles.isEmpty()) return
|
||||
|
||||
if (selectedFiles.size == 1) {
|
||||
// Share single file
|
||||
val file = selectedFiles.first()
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = context.contentResolver.getType(uri) ?: "*/*"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(shareIntent, context.getString(R.string.share_file))
|
||||
)
|
||||
} else {
|
||||
// Share multiple files
|
||||
val uris = selectedFiles.map { file ->
|
||||
FileProvider.getUriForFile(
|
||||
try {
|
||||
if (selectedFiles.size == 1) {
|
||||
// Share single file
|
||||
val file = selectedFiles.first()
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = context.contentResolver.getType(uri) ?: "*/*"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(shareIntent, context.getString(R.string.share_file))
|
||||
)
|
||||
} else {
|
||||
// Share multiple files
|
||||
val uris = selectedFiles.mapNotNull { file ->
|
||||
try {
|
||||
FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to get URI for file ${file.name}: ${e.message}")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
if (uris.isNotEmpty()) {
|
||||
val shareIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||
type = "*/*"
|
||||
putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(uris))
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(shareIntent, "Share ${selectedFiles.size} files")
|
||||
)
|
||||
} else {
|
||||
Toast.makeText(context, "No files could be shared", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
val shareIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||
type = "*/*"
|
||||
putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(uris))
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(shareIntent, "Share ${selectedFiles.size} files")
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to share files: ${e.message}")
|
||||
Toast.makeText(context, "Failed to share files", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
exitSelectionMode()
|
||||
@@ -554,4 +719,48 @@ class FileAdapter(
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force refresh of all selection states
|
||||
* Call this if you notice selection UI issues
|
||||
*/
|
||||
fun refreshSelectionStates() {
|
||||
if (isSelectionMode) {
|
||||
selectedItems.forEach { position ->
|
||||
if (position < itemCount) {
|
||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||
}
|
||||
}
|
||||
// Ensure callback is notified
|
||||
notifySelectionModeChange()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources to prevent memory leaks
|
||||
*/
|
||||
fun cleanup() {
|
||||
try {
|
||||
if (!fileExecutor.isShutdown) {
|
||||
fileExecutor.shutdown()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error shutting down executor: ${e.message}")
|
||||
}
|
||||
|
||||
fileOperationCallback?.clear()
|
||||
fileOperationCallback = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this from the activity's onDestroy()
|
||||
*/
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
cleanup()
|
||||
}
|
||||
|
||||
private fun onSelectionCountChanged(count: Int) {
|
||||
fileOperationCallback?.get()?.onSelectionCountChanged(count)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ import java.io.File
|
||||
class FolderAdapter(
|
||||
private val onFolderClick: (File) -> Unit,
|
||||
private val onFolderLongClick: (File) -> Unit,
|
||||
private val onSelectionModeChanged: (Boolean) -> Unit
|
||||
private val onSelectionModeChanged: (Boolean) -> Unit,
|
||||
private val onSelectionCountChanged: (Int) -> Unit
|
||||
) : ListAdapter<File, FolderAdapter.FolderViewHolder>(FolderDiffCallback()) {
|
||||
|
||||
private val selectedItems = mutableSetOf<Int>()
|
||||
@@ -41,8 +42,7 @@ class FolderAdapter(
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
if (!isSelectionMode) {
|
||||
isSelectionMode = true
|
||||
onSelectionModeChanged(true)
|
||||
enterSelectionMode()
|
||||
onFolderLongClick(folder)
|
||||
toggleSelection(adapterPosition)
|
||||
}
|
||||
@@ -54,12 +54,12 @@ class FolderAdapter(
|
||||
if (selectedItems.contains(position)) {
|
||||
selectedItems.remove(position)
|
||||
if (selectedItems.isEmpty()) {
|
||||
isSelectionMode = false
|
||||
onSelectionModeChanged(false)
|
||||
exitSelectionMode()
|
||||
}
|
||||
} else {
|
||||
selectedItems.add(position)
|
||||
}
|
||||
onSelectionCountChanged(selectedItems.size)
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
@@ -81,10 +81,36 @@ class FolderAdapter(
|
||||
}
|
||||
|
||||
fun clearSelection() {
|
||||
val wasInSelectionMode = isSelectionMode
|
||||
selectedItems.clear()
|
||||
if (wasInSelectionMode) {
|
||||
exitSelectionMode()
|
||||
}
|
||||
onSelectionCountChanged(0)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun onBackPressed(): Boolean {
|
||||
return if (isInSelectionMode()) {
|
||||
clearSelection()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isInSelectionMode(): Boolean {
|
||||
return isSelectionMode
|
||||
}
|
||||
|
||||
private fun enterSelectionMode() {
|
||||
isSelectionMode = true
|
||||
onSelectionModeChanged(true)
|
||||
}
|
||||
|
||||
private fun exitSelectionMode() {
|
||||
isSelectionMode = false
|
||||
onSelectionModeChanged(false)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private class FolderDiffCallback : DiffUtil.ItemCallback<File>() {
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
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
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import devs.org.calculator.R
|
||||
import java.io.File
|
||||
|
||||
class ListFolderAdapter(
|
||||
private val onFolderClick: (File) -> Unit,
|
||||
private val onFolderLongClick: (File) -> Unit,
|
||||
private val onSelectionModeChanged: (Boolean) -> Unit,
|
||||
private val onSelectionCountChanged: (Int) -> Unit
|
||||
) : ListAdapter<File, ListFolderAdapter.FolderViewHolder>(FolderDiffCallback()) {
|
||||
|
||||
private val selectedItems = mutableSetOf<Int>()
|
||||
private var isSelectionMode = false
|
||||
|
||||
inner class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val folderNameTextView: TextView = itemView.findViewById(R.id.folderName)
|
||||
|
||||
val selectedLayer: View = itemView.findViewById(R.id.selectedLayer)
|
||||
|
||||
fun bind(folder: File, onFolderClick: (File) -> Unit, onFolderLongClick: (File) -> Unit, isSelected: Boolean) {
|
||||
folderNameTextView.text = folder.name
|
||||
|
||||
selectedLayer.visibility = if (isSelected) View.VISIBLE else View.GONE
|
||||
|
||||
itemView.setOnClickListener {
|
||||
if (isSelectionMode) {
|
||||
toggleSelection(adapterPosition)
|
||||
} else {
|
||||
onFolderClick(folder)
|
||||
}
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
if (!isSelectionMode) {
|
||||
enterSelectionMode()
|
||||
onFolderLongClick(folder)
|
||||
toggleSelection(adapterPosition)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleSelection(position: Int) {
|
||||
if (selectedItems.contains(position)) {
|
||||
selectedItems.remove(position)
|
||||
if (selectedItems.isEmpty()) {
|
||||
exitSelectionMode()
|
||||
}
|
||||
} else {
|
||||
selectedItems.add(position)
|
||||
}
|
||||
onSelectionCountChanged(selectedItems.size)
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun enterSelectionMode() {
|
||||
isSelectionMode = true
|
||||
onSelectionModeChanged(true)
|
||||
}
|
||||
|
||||
private fun exitSelectionMode() {
|
||||
isSelectionMode = false
|
||||
onSelectionModeChanged(false)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FolderViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_folder_list_style, parent, false)
|
||||
return FolderViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: FolderViewHolder, position: Int) {
|
||||
val folder = getItem(position)
|
||||
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() {
|
||||
val wasInSelectionMode = isSelectionMode
|
||||
selectedItems.clear()
|
||||
if (wasInSelectionMode) {
|
||||
exitSelectionMode()
|
||||
}
|
||||
onSelectionCountChanged(0)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun onBackPressed(): Boolean {
|
||||
return if (isInSelectionMode()) {
|
||||
clearSelection()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isInSelectionMode(): Boolean {
|
||||
return isSelectionMode
|
||||
}
|
||||
|
||||
private class FolderDiffCallback : DiffUtil.ItemCallback<File>() {
|
||||
override fun areItemsTheSame(oldItem: File, newItem: File): Boolean {
|
||||
return oldItem.absolutePath == newItem.absolutePath
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: File, newItem: File): Boolean {
|
||||
return oldItem.name == newItem.name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,15 @@ class PrefsUtil(context: Context) {
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun setBoolean(key:String, value: Boolean){
|
||||
return prefs.edit().putBoolean(key,value).apply()
|
||||
|
||||
}
|
||||
|
||||
fun getBoolean(key: String, defValue: Boolean = false): Boolean{
|
||||
return prefs.getBoolean(key,defValue)
|
||||
}
|
||||
|
||||
fun resetPassword(){
|
||||
prefs.edit()
|
||||
.remove("password")
|
||||
|
||||
6
app/src/main/res/drawable/bottom_corner.xml
Normal file
6
app/src/main/res/drawable/bottom_corner.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<corners android:bottomLeftRadius="15dp" android:bottomRightRadius="15dp"/>
|
||||
<solid android:color="?attr/cardForegroundColor"/>
|
||||
</shape>
|
||||
@@ -5,8 +5,8 @@
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M224,480h640a32,32 0,1 1,0 64H224a32,32 0,0 1,0 -64z"
|
||||
android:fillColor="@color/textColor"/>
|
||||
android:fillColor="@color/svgTintColor"/>
|
||||
<path
|
||||
android:pathData="m237.2,512 l265.4,265.3a32,32 0,0 1,-45.3 45.3l-288,-288a32,32 0,0 1,0 -45.3l288,-288a32,32 0,1 1,45.3 45.3L237.2,512z"
|
||||
android:fillColor="@color/textColor"/>
|
||||
android:fillColor="@color/svgTintColor"/>
|
||||
</vector>
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_edit.xml
Normal file
9
app/src/main/res/drawable/ic_edit.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="800dp"
|
||||
android:height="800dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"
|
||||
android:fillColor="?attr/colorPrimary"/>
|
||||
</vector>
|
||||
37
app/src/main/res/drawable/ic_folder_yellow.xml
Normal file
37
app/src/main/res/drawable/ic_folder_yellow.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="800dp"
|
||||
android:height="800dp"
|
||||
android:viewportWidth="32"
|
||||
android:viewportHeight="32">
|
||||
<path
|
||||
android:pathData="M2.909,3.5L11.283,3.5C12.441,3.5 13.551,3.96 14.369,4.778L14.722,5.131C15.54,5.949 16.65,6.409 17.807,6.409L23.273,6.409C24.076,6.409 24.762,6.693 25.33,7.261C25.898,7.829 26.182,8.515 26.182,9.318L26.182,25.318C26.182,26.122 25.898,26.807 25.33,27.375C24.762,27.943 24.076,28.227 23.273,28.227L2.909,28.227C2.106,28.227 1.42,27.943 0.852,27.375C0.284,26.807 0,26.122 0,25.318L0,6.409C0,5.606 0.284,4.92 0.852,4.352C1.42,3.784 2.106,3.5 2.909,3.5Z"
|
||||
android:fillType="evenOdd">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="16"
|
||||
android:startY="3.5"
|
||||
android:endX="16"
|
||||
android:endY="19.854"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FFFBA200"/>
|
||||
<item android:offset="1" android:color="#FFFF7300"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M5.818,25.318L5.818,12.227C5.818,11.424 6.102,10.738 6.67,10.17C7.238,9.602 7.924,9.318 8.727,9.318L29.091,9.318C29.894,9.318 30.58,9.602 31.148,10.17C31.716,10.738 32,11.424 32,12.227L32,25.318C32,26.122 31.716,26.807 31.148,27.375C30.58,27.943 29.894,28.227 29.091,28.227L2.909,28.227C3.712,28.227 4.398,27.943 4.966,27.375C5.534,26.807 5.818,26.122 5.818,25.318Z"
|
||||
android:fillType="evenOdd">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="17.454"
|
||||
android:startY="9.318"
|
||||
android:endX="17.454"
|
||||
android:endY="28.227"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FFFAC227"/>
|
||||
<item android:offset="1" android:color="#FFFAA627"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_github.xml
Normal file
10
app/src/main/res/drawable/ic_github.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="20"
|
||||
android:viewportWidth="20"
|
||||
android:width="24dp">
|
||||
|
||||
<path android:fillColor="@color/black" android:fillType="evenOdd" android:pathData="M10,0C15.523,0 20,4.59 20,10.253C20,14.782 17.138,18.624 13.167,19.981C12.66,20.082 12.48,19.762 12.48,19.489C12.48,19.151 12.492,18.047 12.492,16.675C12.492,15.719 12.172,15.095 11.813,14.777C14.04,14.523 16.38,13.656 16.38,9.718C16.38,8.598 15.992,7.684 15.35,6.966C15.454,6.707 15.797,5.664 15.252,4.252C15.252,4.252 14.414,3.977 12.505,5.303C11.706,5.076 10.85,4.962 10,4.958C9.15,4.962 8.295,5.076 7.497,5.303C5.586,3.977 4.746,4.252 4.746,4.252C4.203,5.664 4.546,6.707 4.649,6.966C4.01,7.684 3.619,8.598 3.619,9.718C3.619,13.646 5.954,14.526 8.175,14.785C7.889,15.041 7.63,15.493 7.54,16.156C6.97,16.418 5.522,16.871 4.63,15.304C4.63,15.304 4.101,14.319 3.097,14.247C3.097,14.247 2.122,14.234 3.029,14.87C3.029,14.87 3.684,15.185 4.139,16.37C4.139,16.37 4.726,18.2 7.508,17.58C7.513,18.437 7.522,19.245 7.522,19.489C7.522,19.76 7.338,20.077 6.839,19.982C2.865,18.627 0,14.783 0,10.253C0,4.59 4.478,0 10,0" android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_grid.xml
Normal file
12
app/src/main/res/drawable/ic_grid.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="169dp"
|
||||
android:height="169dp"
|
||||
android:viewportWidth="35.28"
|
||||
android:viewportHeight="35.28">
|
||||
<path
|
||||
android:pathData="M27.64,3.64L23.64,3.64C21.431,3.64 19.64,5.431 19.64,7.64L19.64,11.64C19.64,13.849 21.431,15.64 23.64,15.64L27.64,15.64C29.849,15.64 31.64,13.849 31.64,11.64L31.64,7.64C31.64,5.431 29.849,3.64 27.64,3.64L27.64,3.64ZM27.64,19.64L23.64,19.64C21.431,19.64 19.64,21.431 19.64,23.64L19.64,27.64C19.64,29.849 21.431,31.64 23.64,31.64L27.64,31.64C29.849,31.64 31.64,29.849 31.64,27.64L31.64,23.64C31.64,21.431 29.849,19.64 27.64,19.64L27.64,19.64ZM11.64,19.64L7.64,19.64C5.431,19.64 3.64,21.431 3.64,23.64L3.64,27.64C3.64,29.849 5.431,31.64 7.64,31.64L11.64,31.64C13.849,31.64 15.64,29.849 15.64,27.64L15.64,23.64C15.64,21.431 13.849,19.64 11.64,19.64L11.64,19.64ZM11.64,3.64L7.64,3.64C5.431,3.64 3.64,5.431 3.64,7.64L3.64,11.64C3.64,13.849 5.431,15.64 7.64,15.64L11.64,15.64C13.849,15.64 15.64,13.849 15.64,11.64L15.64,7.64C15.64,5.431 13.849,3.64 11.64,3.64L11.64,3.64Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_list.xml
Normal file
9
app/src/main/res/drawable/ic_list.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="800dp"
|
||||
android:height="800dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M4,13L2,13L2,11L4,11ZM14,11L6,11v2h8ZM4,7L2,7L2,9L4,9ZM14,7L6,7L6,9h8ZM4,3L2,3L2,5L4,5ZM14,3L6,3L6,5h8Z"
|
||||
android:fillColor="?attr/colorPrimary"/>
|
||||
</vector>
|
||||
8
app/src/main/res/drawable/ic_more.xml
Normal file
8
app/src/main/res/drawable/ic_more.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M12,12H12.01M12,6H12.01M12,18H12.01M13,12C13,12.552 12.552,13 12,13C11.448,13 11,12.552 11,12C11,11.448 11.448,11 12,11C12.552,11 13,11.448 13,12ZM13,18C13,18.552 12.552,19 12,19C11.448,19 11,18.552 11,18C11,17.448 11.448,17 12,17C12.552,17 13,17.448 13,18ZM13,6C13,6.552 12.552,7 12,7C11.448,7 11,6.552 11,6C11,5.448 11.448,5 12,5C12.552,5 13,5.448 13,6Z" android:strokeColor="?attr/colorPrimary" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2"/>
|
||||
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_play_circle.xml
Normal file
12
app/src/main/res/drawable/ic_play_circle.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="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M34.6,23.3 L18.1,13.2c-0.6,-0.4 -1.1,-0.1 -1.1,0.6V34.2c0,0.7 0.5,1 1.1,0.6L34.6,24.7A0.8,0.8 0,0 0,34.6 23.3Z"/>
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M24,2A22,22 0,1 0,46 24,21.9 21.9,0 0,0 24,2ZM24,42A18,18 0,1 1,42 24,18.1 18.1,0 0,1 24,42Z"/>
|
||||
</vector>
|
||||
@@ -1,11 +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="1" android:fillColor="?attr/colorPrimary" 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="1" android:fillColor="?attr/colorPrimary" 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:fillAlpha="1" android:fillColor="?attr/colorPrimary" 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"/>
|
||||
<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="?attr/colorPrimary" android:strokeLineCap="round" android:strokeWidth="1.5"/>
|
||||
|
||||
</vector>
|
||||
|
||||
9
app/src/main/res/drawable/ic_settings.xml
Normal file
9
app/src/main/res/drawable/ic_settings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="800dp"
|
||||
android:height="800dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,13.743l-1,0.579a1,1 0,0 0,-0.366 1.366l1.488,2.578a1,1 0,0 0,1.366 0.366L6.5,18.05a1.987,1.987 0,0 1,1.986 0l0.02,0.011a1.989,1.989 0,0 1,1 1.724V21a1,1 0,0 0,1 1h3a1,1 0,0 0,1 -1V19.782a1.985,1.985 0,0 1,0.995 -1.721l0.021,-0.012a1.987,1.987 0,0 1,1.986 0l1.008,0.582a1,1 0,0 0,1.366 -0.366l1.488,-2.578A1,1 0,0 0,21 14.322l-1,-0.579a1.994,1.994 0,0 1,-1 -1.733v-0.021a1.991,1.991 0,0 1,1 -1.732l1,-0.579a1,1 0,0 0,0.366 -1.366L19.876,5.734a1,1 0,0 0,-1.366 -0.366L17.5,5.95a1.987,1.987 0,0 1,-1.986 0L15.5,5.94a1.989,1.989 0,0 1,-1 -1.724V3a1,1 0,0 0,-1 -1h-3a1,1 0,0 0,-1 1V4.294A1.856,1.856 0,0 1,8.57 5.9l-0.153,0.088a1.855,1.855 0,0 1,-1.853 0L5.49,5.368a1,1 0,0 0,-1.366 0.366L2.636,8.312A1,1 0,0 0,3 9.678l1,0.579A1.994,1.994 0,0 1,5 11.99v0.021A1.991,1.991 0,0 1,4 13.743ZM12,9a3,3 0,1 1,-3 3A3,3 0,0 1,12 9Z"
|
||||
android:fillColor="?attr/colorPrimary"/>
|
||||
</vector>
|
||||
@@ -1,8 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="512" android:viewportWidth="512" android:width="24dp">
|
||||
|
||||
<path android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M21.409,9.353C23.531,10.507 23.531,13.493 21.409,14.647L8.597,21.615C6.534,22.736 4,21.276 4,18.967L4,5.033C4,2.724 6.534,1.264 8.597,2.385L21.409,9.353Z"/>
|
||||
<path android:fillColor="?attr/colorPrimary" android:pathData="M464.7,221.5L86.1,7.3C52.5,-11.7 25,7.5 25,50v412c0,42.5 27.5,61.7 61.1,42.7l378.6,-214.1C498.2,271.5 498.2,240.5 464.7,221.5z"/>
|
||||
|
||||
</vector>
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
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"/>
|
||||
android:fillColor="@color/black"/>
|
||||
</vector>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Change Password"
|
||||
android:text="@string/change_password"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:hint="Enter Old Password"
|
||||
android:hint="@string/enter_old_password"
|
||||
app:endIconMode="password_toggle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTitle">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Enter New Password"
|
||||
android:hint="@string/enter_new_password"
|
||||
app:endIconMode="password_toggle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilOldPassword">
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:padding="12dp"
|
||||
android:text="Change Password"
|
||||
android:text="@string/change_password"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilNewPassword" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@@ -70,7 +70,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Forgot Password?"
|
||||
android:text="@string/forgot_password"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnChangePassword" />
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,145 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:layout_marginTop="50dp"
|
||||
android:padding="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/noItems"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@drawable/ic_no_items" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noItemsTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/no_items_available_add_one_by_clicking_on_the_plus_button"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actionModeBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:elevation="4dp"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/selectedCount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnDelete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:tint="@android:color/white" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnClose"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_close"
|
||||
android:tint="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabCreateFolder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/create_folder"
|
||||
app:srcCompat="@drawable/ic_create_new_folder" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAdd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_files"
|
||||
app:srcCompat="@drawable/ic_add" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAddImage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_image"
|
||||
app:srcCompat="@drawable/ic_image" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAddVideo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_video"
|
||||
app:srcCompat="@drawable/ic_video" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAddAudio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_audio"
|
||||
app:srcCompat="@drawable/ic_audio" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAddDocument"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_document"
|
||||
app:srcCompat="@drawable/ic_document" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp" />
|
||||
|
||||
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAdd"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="35dp"
|
||||
android:src="@android:drawable/ic_input_add" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -41,10 +41,48 @@
|
||||
<ImageButton
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_setting"
|
||||
android:src="@drawable/ic_edit"
|
||||
android:scaleType="fitCenter"
|
||||
android:padding="9dp"
|
||||
android:visibility="gone"
|
||||
android:background="#00000000"
|
||||
android:id="@+id/edit"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="#00000000"
|
||||
android:padding="9dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/menuButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_more"
|
||||
android:scaleType="fitCenter"
|
||||
android:padding="9dp"
|
||||
android:visibility="gone"
|
||||
android:background="#00000000"/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_list"
|
||||
android:scaleType="fitCenter"
|
||||
android:background="#00000000"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/folderOrientation"/>
|
||||
<ImageButton
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_settings"
|
||||
android:scaleType="fitCenter"
|
||||
android:background="#00000000"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/settings"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -88,90 +126,28 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addImage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/add_image"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:text="@string/add_image"
|
||||
android:visibility="gone"
|
||||
app:fabCustomSize="48dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addVideo"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addVideo"
|
||||
app:layout_constraintStart_toStartOf="@+id/addVideo" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addVideo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:src="@drawable/video_add"
|
||||
android:text="@string/add_image"
|
||||
android:visibility="gone"
|
||||
app:fabCustomSize="49dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addAudio"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addAudio"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="@+id/addAudio" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addAudio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:src="@drawable/music_add"
|
||||
android:text="@string/add_image"
|
||||
app:fabCustomSize="51dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addDocument"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addDocument"
|
||||
app:layout_constraintStart_toStartOf="@+id/addDocument" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addDocument"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/document_add"
|
||||
android:text="@string/add_image"
|
||||
android:layout_marginBottom="10dp"
|
||||
app:fabCustomSize="54dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/fabExpend"
|
||||
app:layout_constraintEnd_toEndOf="@+id/fabExpend"
|
||||
app:layout_constraintStart_toStartOf="@+id/fabExpend" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addFolder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_folder_add"
|
||||
android:text="@string/add_image"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:tint="@color/white"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:fabCustomSize="57dp" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabExpend"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/ic_add"
|
||||
android:visibility="gone"
|
||||
android:text="@string/add_image"
|
||||
app:fabCustomSize="60dp"
|
||||
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:tint="@color/white"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginEnd="16dp"
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2"
|
||||
android:minHeight="300dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_horizontal|bottom"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/btnImages"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/btnAudio"
|
||||
app:layout_constraintEnd_toStartOf="@id/btnVideos"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="Images"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/btnVideos"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/btnDocs"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/btnImages"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="Videos"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_horizontal|top"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/btnAudio"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/btnDocs"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnImages">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="Audio"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/btnDocs"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/btnAudio"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnVideos">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="Documents"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
@@ -11,7 +11,8 @@
|
||||
android:id="@+id/displayContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_margin="0dp"
|
||||
android:background="@drawable/bottom_corner"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -40,14 +41,14 @@
|
||||
android:id="@+id/display"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoSizeMaxTextSize="48sp"
|
||||
android:autoSizeMaxTextSize="70sp"
|
||||
android:autoSizeMinTextSize="16sp"
|
||||
android:autoSizeStepGranularity="2sp"
|
||||
android:gravity="end|bottom"
|
||||
android:autoSizeTextType="uniform"
|
||||
android:padding="10dp"
|
||||
android:text="0"
|
||||
android:textSize="48sp"
|
||||
android:text=""
|
||||
android:textSize="70sp"
|
||||
tools:ignore="Suspicious0dp" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -57,7 +58,7 @@
|
||||
android:id="@+id/total"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoSizeMaxTextSize="26sp"
|
||||
android:autoSizeMaxTextSize="40sp"
|
||||
android:autoSizeMinTextSize="24sp"
|
||||
android:autoSizeStepGranularity="2sp"
|
||||
android:autoSizeTextType="uniform"
|
||||
@@ -65,7 +66,7 @@
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:text=""
|
||||
android:textSize="26sp"
|
||||
android:textSize="40sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -183,6 +184,7 @@
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="@color/white"
|
||||
android:text="×"
|
||||
android:textSize="30sp"
|
||||
app:cornerRadius="15dp" />
|
||||
@@ -236,6 +238,7 @@
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="@color/white"
|
||||
android:text="-"
|
||||
android:textSize="30sp"
|
||||
app:cornerRadius="15dp" />
|
||||
@@ -289,6 +292,7 @@
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="@color/white"
|
||||
android:text="+"
|
||||
android:textSize="30sp"
|
||||
app:cornerRadius="15dp" />
|
||||
@@ -331,6 +335,7 @@
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="@color/white"
|
||||
android:text="="
|
||||
android:textSize="30sp"
|
||||
app:cornerRadius="15dp" />
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
android:textSize="22sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:text="Preview File"/>
|
||||
android:text="@string/preview_file"/>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
@@ -60,7 +60,7 @@
|
||||
android:minWidth="120dp"
|
||||
android:layout_weight="1"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:text="Unhide" />
|
||||
android:text="@string/un_hide" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/delete"
|
||||
@@ -69,7 +69,7 @@
|
||||
android:layout_weight="1"
|
||||
android:layout_margin="6dp"
|
||||
android:minWidth="120dp"
|
||||
android:text="Delete" />
|
||||
android:text="@string/delete" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -1,10 +1,291 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activities.SettingsActivity">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/toolBar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_back"
|
||||
android:scaleType="fitCenter"
|
||||
android:background="#00000000"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/back"/>
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings"
|
||||
android:textSize="22sp"
|
||||
android:singleLine="true"
|
||||
android:padding="4dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/folderName"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- App Details Section -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_details"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardElevation="5dp">
|
||||
<ImageView
|
||||
android:id="@+id/appLogo"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/full_app_name"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/version"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/githubButton"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_github" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Developer Details Section -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/developer_details"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/binondi_borthakur"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/devGithubButton"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_github" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Theme Settings Section -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/theme_settings"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/dynamicThemeSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/dynamic_theme"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/themeModeSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/theme_mode"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/themeRadioGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/lightThemeRadio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/light" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/darkThemeRadio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dark" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/systemThemeRadio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/system_default" />
|
||||
</RadioGroup>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Security Settings Section -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/security_settings"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/screenshotRestrictionSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/restrict_screenshots_in_hidden_section"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="10dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_settings"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/showFileNames"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/show_file_names"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -12,7 +12,7 @@
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Setup Password"
|
||||
android:text="@string/setup_password"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:hint="Enter Password"
|
||||
android:hint="@string/enter_password"
|
||||
app:endIconMode="password_toggle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTitle">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Confirm Password"
|
||||
android:hint="@string/confirm_password"
|
||||
app:endIconMode="password_toggle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilPassword">
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Security Question (For Password Reset)"
|
||||
android:hint="@string/security_question_for_password_reset"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilConfirmPassword">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
@@ -75,7 +75,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Security Answer"
|
||||
android:hint="@string/security_answer"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilSecurityQuestion">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
@@ -91,7 +91,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:padding="12dp"
|
||||
android:text="Save Password"
|
||||
android:text="@string/save_password"
|
||||
app:layout_constraintTop_toBottomOf="@id/tilSecurityAnswer" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@@ -100,7 +100,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Forgot Password?"
|
||||
android:text="@string/forgot_password"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnSavePassword" />
|
||||
|
||||
169
app/src/main/res/layout/activity_view_folder.xml
Normal file
169
app/src/main/res/layout/activity_view_folder.xml
Normal file
@@ -0,0 +1,169 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
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:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activities.ViewFolderActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/toolBar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_back"
|
||||
android:scaleType="fitCenter"
|
||||
android:background="#00000000"
|
||||
android:padding="8dp"
|
||||
android:id="@+id/back"/>
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hidden_space"
|
||||
android:textSize="22sp"
|
||||
android:singleLine="true"
|
||||
android:padding="4dp"
|
||||
android:textStyle="bold"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/folderName"/>
|
||||
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/menuButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@drawable/ic_more"
|
||||
android:scaleType="fitCenter"
|
||||
android:padding="7dp"
|
||||
android:visibility="gone"
|
||||
android:background="#00000000"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolBar">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/noItems"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@drawable/ic_no_items" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noItemsTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/no_items_available_add_one_by_clicking_on_the_plus_button"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addImage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/add_image"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:text="@string/add_image"
|
||||
app:tint="@color/white"
|
||||
android:visibility="gone"
|
||||
app:fabCustomSize="48dp"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addVideo"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addVideo"
|
||||
app:layout_constraintStart_toStartOf="@+id/addVideo" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addVideo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:src="@drawable/video_add"
|
||||
android:text="@string/add_image"
|
||||
app:fabCustomSize="49dp"
|
||||
android:visibility="gone"
|
||||
app:tint="@color/white"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addAudio"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addAudio"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="@+id/addAudio" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addAudio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:src="@drawable/music_add"
|
||||
android:text="@string/add_image"
|
||||
app:fabCustomSize="51dp"
|
||||
android:visibility="gone"
|
||||
app:tint="@color/white"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/addDocument"
|
||||
app:layout_constraintEnd_toEndOf="@+id/addDocument"
|
||||
app:layout_constraintStart_toStartOf="@+id/addDocument" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/addDocument"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/document_add"
|
||||
android:text="@string/add_image"
|
||||
android:layout_marginBottom="10dp"
|
||||
app:fabCustomSize="54dp"
|
||||
app:tint="@color/white"
|
||||
android:visibility="gone"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/fabExpend"
|
||||
app:layout_constraintEnd_toEndOf="@+id/fabExpend"
|
||||
app:layout_constraintStart_toStartOf="@+id/fabExpend" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabExpend"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/ic_add"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:text="@string/add_image"
|
||||
app:fabCustomSize="60dp"
|
||||
app:tint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -5,12 +5,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
app:cardCornerRadius="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -55,19 +54,22 @@
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:maxLines="1"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</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>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<ImageView
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:background="@drawable/gradient_bg"
|
||||
android:padding="3dp"
|
||||
android:src="@drawable/selected"
|
||||
android:layout_gravity="end"
|
||||
android:visibility="visible"
|
||||
app:tint="#fff" />
|
||||
</FrameLayout>
|
||||
97
app/src/main/res/layout/item_folder_list_style.xml
Normal file
97
app/src/main/res/layout/item_folder_list_style.xml
Normal file
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/selectedLayer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:alpha="0.3"
|
||||
android:background="?attr/colorControlNormal"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
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">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/folderIcon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:padding="8dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_folder" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="10dp"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/folderName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timeModified"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:text=""
|
||||
android:visibility="gone"
|
||||
android:textColor="#767676"
|
||||
android:maxLines="1"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:background="@drawable/gradient_bg"
|
||||
android:padding="3dp"
|
||||
android:src="@drawable/selected"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="#fff" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</FrameLayout>
|
||||
@@ -13,18 +13,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<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" />
|
||||
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardView"
|
||||
@@ -38,36 +27,49 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fileIconImageView"
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/add_image" />
|
||||
android:layout_height="match_parent">
|
||||
<ImageView
|
||||
android:id="@+id/fileIconImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/add_image" />
|
||||
<LinearLayout
|
||||
android:id="@+id/selectedLayer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:alpha="0.3"
|
||||
android:background="?attr/colorControlNormal"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
<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>
|
||||
<ImageView
|
||||
android:id="@+id/videoPlay"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:contentDescription=""
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:visibility="gone"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/play"
|
||||
android:src="@drawable/ic_play_circle"
|
||||
android:layout_gravity="center"/>
|
||||
<ImageView
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:padding="3dp"
|
||||
app:tint="#fff"
|
||||
android:visibility="gone"
|
||||
android:src="@drawable/selected"
|
||||
android:background="@drawable/gradient_bg"
|
||||
android:layout_gravity="end"/>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color name="white">#FF000000</color>
|
||||
<color name="black">#FFFFFFFF</color>
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
<color name="colorPrimaryVariant">#00C15C</color>
|
||||
<color name="colorSecondary">#39FF97</color>
|
||||
<color name="textColor">#ffffff</color>
|
||||
<color name="svgTintColor" tools:ignore="MissingDefaultResource">#ffffff</color>
|
||||
</resources>
|
||||
@@ -1,20 +1,15 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.Calculator" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Primary brand color -->
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<!-- Secondary brand color -->
|
||||
<item name="colorAccent">@color/primary</item>
|
||||
<item name="colorSecondary">@color/colorSecondary</item>
|
||||
<item name="colorSecondaryVariant">@color/colorSecondary</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="fontFamily">@font/ubuntu_regular</item>
|
||||
<!-- Status bar color -->
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
|
||||
<!-- Enable window decor fitting -->
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
<color name="colorPrimaryVariant">#00C15C</color>
|
||||
<color name="colorSecondary">#39FF97</color>
|
||||
<color name="textColor">#000000</color>
|
||||
<color name="svgTintColor" tools:ignore="MissingDefaultResource">#000000</color>
|
||||
</resources>
|
||||
@@ -91,4 +91,39 @@
|
||||
<string name="failed_to_create_uri_for_file">Failed to create URI for file</string>
|
||||
<string name="error_unhiding_file">Error unhiding file: %1$s</string>
|
||||
<string name="select_multiple">Select Multiple</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="binondi_borthakur">Binondi Borthakur</string>
|
||||
<string name="dynamic_theme">Dynamic Theme</string>
|
||||
<string name="theme_mode">Theme Mode</string>
|
||||
<string name="light">Light</string>
|
||||
<string name="dark">Dark</string>
|
||||
<string name="system_default">System Default</string>
|
||||
<string name="full_app_name">Calculator Hide Files</string>
|
||||
<string name="developer_details">Developer Details</string>
|
||||
<string name="theme_settings">Theme Settings</string>
|
||||
<string name="files_deleted_successfully">Files deleted successfully</string>
|
||||
<string name="some_files_could_not_be_deleted">Some files could not be deleted</string>
|
||||
<string name="un_hide_files">Unhide Files</string>
|
||||
<string name="are_you_sure_you_want_to_un_hide_selected_files">Are you sure you want to unhide the selected files?</string>
|
||||
<string name="files_unhidden_successfully">Files unhidden successfully</string>
|
||||
<string name="some_files_could_not_be_unhidden">Some files could not be unhidden</string>
|
||||
<string name="copy_to_another_folder">Copy to Another Folder</string>
|
||||
<string name="move_to_another_folder">Move to Another Folder</string>
|
||||
<string name="select_destination_folder">Select Destination Folder</string>
|
||||
<string name="no_folders_available">No other folders available</string>
|
||||
<string name="change_password">Change Password</string>
|
||||
<string name="enter_old_password">Enter Old Password</string>
|
||||
<string name="enter_new_password">Enter New Password</string>
|
||||
<string name="forgot_password">Forgot Password?</string>
|
||||
<string name="preview_file">Preview File</string>
|
||||
<string name="show_file_names">Show File Names</string>
|
||||
<string name="app_settings">App Settings</string>
|
||||
<string name="restrict_screenshots_in_hidden_section">Restrict Screenshots in Hidden Section</string>
|
||||
<string name="security_settings">Security Settings</string>
|
||||
<string name="version">Version 1.3</string>
|
||||
<string name="app_details">App Details</string>
|
||||
<string name="setup_password">Setup Password</string>
|
||||
<string name="security_question_for_password_reset">Security Question (For Password Reset)</string>
|
||||
<string name="security_answer">Security Answer</string>
|
||||
<string name="save_password">Save Password</string>
|
||||
</resources>
|
||||
@@ -1,20 +1,18 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
|
||||
<style name="Base.Theme.Calculator" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Primary brand color -->
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
|
||||
<item name="colorAccent">@color/primary</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color -->
|
||||
<item name="colorSecondary">@color/colorSecondary</item>
|
||||
<item name="colorSecondaryVariant">@color/colorSecondary</item>
|
||||
<item name="colorOnSecondary">@color/white</item>
|
||||
<item name="fontFamily">@font/ubuntu_regular</item>
|
||||
<!-- Status bar color -->
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="colorControlNormal">#483CFF61</item>
|
||||
|
||||
<!-- Enable window decor fitting -->
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user