Changes For Folder Feature
This commit is contained in:
37
app/release/output-metadata.json
Normal file
37
app/release/output-metadata.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"artifactType": {
|
||||||
|
"type": "APK",
|
||||||
|
"kind": "Directory"
|
||||||
|
},
|
||||||
|
"applicationId": "devs.org.calculator",
|
||||||
|
"variantName": "release",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "SINGLE",
|
||||||
|
"filters": [],
|
||||||
|
"attributes": [],
|
||||||
|
"versionCode": 4,
|
||||||
|
"versionName": "1.3",
|
||||||
|
"outputFile": "app-release.apk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elementType": "File",
|
||||||
|
"baselineProfiles": [
|
||||||
|
{
|
||||||
|
"minApi": 28,
|
||||||
|
"maxApi": 30,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/1/app-release.dm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minApi": 31,
|
||||||
|
"maxApi": 2147483647,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/0/app-release.dm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minSdkVersionForDexing": 26
|
||||||
|
}
|
||||||
@@ -66,6 +66,10 @@
|
|||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/file_paths" />
|
android:resource="@xml/file_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.app.icon"
|
||||||
|
android:resource="@mipmap/ic_launcher_monochrome" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -3,19 +3,14 @@ package devs.org.calculator
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.google.android.material.color.DynamicColors
|
import com.google.android.material.color.DynamicColors
|
||||||
|
import devs.org.calculator.utils.PrefsUtil
|
||||||
|
|
||||||
class CalculatorApp : Application() {
|
class CalculatorApp : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
val prefs = PrefsUtil(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)
|
val themeMode = prefs.getInt("theme_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
AppCompatDelegate.setDefaultNightMode(themeMode)
|
AppCompatDelegate.setDefaultNightMode(themeMode)
|
||||||
|
|
||||||
// Apply dynamic colors only if dynamic theme is enabled
|
|
||||||
if (prefs.getBoolean("dynamic_theme", true)) {
|
if (prefs.getBoolean("dynamic_theme", true)) {
|
||||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.os.Bundle
|
|||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
@@ -14,6 +13,7 @@ import android.widget.Toast
|
|||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import devs.org.calculator.R
|
import devs.org.calculator.R
|
||||||
import devs.org.calculator.adapters.FolderAdapter
|
import devs.org.calculator.adapters.FolderAdapter
|
||||||
@@ -36,22 +36,20 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
private var folderAdapter: FolderAdapter? = null
|
private var folderAdapter: FolderAdapter? = null
|
||||||
private var listFolderAdapter: ListFolderAdapter? = null
|
private var listFolderAdapter: ListFolderAdapter? = null
|
||||||
private val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
private val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
||||||
|
private val prefs:PrefsUtil by lazy { PrefsUtil(this) }
|
||||||
|
|
||||||
private val mainHandler = Handler(Looper.getMainLooper())
|
private val mainHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "HiddenActivity"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityHiddenBinding.inflate(layoutInflater)
|
binding = ActivityHiddenBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
fileManager = FileManager(this, this)
|
fileManager = FileManager(this, this)
|
||||||
folderManager = FolderManager(this)
|
folderManager = FolderManager()
|
||||||
dialogUtil = DialogUtil(this)
|
dialogUtil = DialogUtil(this)
|
||||||
|
|
||||||
|
|
||||||
setupInitialUIState()
|
setupInitialUIState()
|
||||||
setupClickListeners()
|
setupClickListeners()
|
||||||
setupBackPressedHandler()
|
setupBackPressedHandler()
|
||||||
@@ -100,20 +98,17 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.folderOrientation.setOnClickListener {
|
binding.folderOrientation.setOnClickListener {
|
||||||
// Switch between grid mode and list mode
|
|
||||||
val currentIsList = PrefsUtil(this).getBoolean("isList", false)
|
val currentIsList = PrefsUtil(this).getBoolean("isList", false)
|
||||||
val newIsList = !currentIsList
|
val newIsList = !currentIsList
|
||||||
|
|
||||||
if (newIsList) {
|
if (newIsList) {
|
||||||
// Switch to list view
|
|
||||||
showListUI()
|
showListUI()
|
||||||
PrefsUtil(this).setBoolean("isList", true)
|
PrefsUtil(this).setBoolean("isList", true)
|
||||||
binding.folderOrientation.setImageResource(R.drawable.ic_grid)
|
binding.folderOrientation.setIconResource(R.drawable.ic_grid)
|
||||||
} else {
|
} else {
|
||||||
// Switch to grid view
|
|
||||||
showGridUI()
|
showGridUI()
|
||||||
PrefsUtil(this).setBoolean("isList", false)
|
PrefsUtil(this).setBoolean("isList", false)
|
||||||
binding.folderOrientation.setImageResource(R.drawable.ic_list)
|
binding.folderOrientation.setIconResource(R.drawable.ic_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,11 +136,10 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
showEmptyState()
|
showEmptyState()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Hidden directory is not accessible: ${hiddenDir.absolutePath}")
|
|
||||||
showEmptyState()
|
showEmptyState()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error listing folders: ${e.message}")
|
|
||||||
showEmptyState()
|
showEmptyState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +167,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
folderManager.createFolder(hiddenDir, newName)
|
folderManager.createFolder(hiddenDir, newName)
|
||||||
refreshCurrentView()
|
refreshCurrentView()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error creating folder: ${e.message}")
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@HiddenActivity,
|
this@HiddenActivity,
|
||||||
"Failed to create folder",
|
"Failed to create folder",
|
||||||
@@ -220,11 +213,9 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
showEmptyState()
|
showEmptyState()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Hidden directory is not accessible: ${hiddenDir.absolutePath}")
|
|
||||||
showEmptyState()
|
showEmptyState()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error listing folders: ${e.message}")
|
|
||||||
showEmptyState()
|
showEmptyState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,8 +223,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
private fun showFolderList(folders: List<File>) {
|
private fun showFolderList(folders: List<File>) {
|
||||||
binding.noItems.visibility = View.GONE
|
binding.noItems.visibility = View.GONE
|
||||||
binding.recyclerView.visibility = View.VISIBLE
|
binding.recyclerView.visibility = View.VISIBLE
|
||||||
|
|
||||||
// Clear the existing adapter to avoid conflicts
|
|
||||||
listFolderAdapter = null
|
listFolderAdapter = null
|
||||||
|
|
||||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 2)
|
binding.recyclerView.layoutManager = GridLayoutManager(this, 2)
|
||||||
@@ -247,14 +236,13 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
onSelectionModeChanged = { isSelectionMode ->
|
onSelectionModeChanged = { isSelectionMode ->
|
||||||
handleFolderSelectionModeChange(isSelectionMode)
|
handleFolderSelectionModeChange(isSelectionMode)
|
||||||
},
|
},
|
||||||
onSelectionCountChanged = { selectedCount ->
|
onSelectionCountChanged = { _ ->
|
||||||
updateEditButtonVisibility()
|
updateEditButtonVisibility()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
binding.recyclerView.adapter = folderAdapter
|
binding.recyclerView.adapter = folderAdapter
|
||||||
folderAdapter?.submitList(folders)
|
folderAdapter?.submitList(folders)
|
||||||
|
|
||||||
// Ensure proper icon state for folder view
|
|
||||||
if (folderAdapter?.isInSelectionMode() != true) {
|
if (folderAdapter?.isInSelectionMode() != true) {
|
||||||
showFolderViewIcons()
|
showFolderViewIcons()
|
||||||
}
|
}
|
||||||
@@ -262,8 +250,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
private fun showFolderListStyle(folders: List<File>) {
|
private fun showFolderListStyle(folders: List<File>) {
|
||||||
binding.noItems.visibility = View.GONE
|
binding.noItems.visibility = View.GONE
|
||||||
binding.recyclerView.visibility = View.VISIBLE
|
binding.recyclerView.visibility = View.VISIBLE
|
||||||
|
|
||||||
// Clear the existing adapter to avoid conflicts
|
|
||||||
folderAdapter = null
|
folderAdapter = null
|
||||||
|
|
||||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 1)
|
binding.recyclerView.layoutManager = GridLayoutManager(this, 1)
|
||||||
@@ -277,14 +263,13 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
onSelectionModeChanged = { isSelectionMode ->
|
onSelectionModeChanged = { isSelectionMode ->
|
||||||
handleFolderSelectionModeChange(isSelectionMode)
|
handleFolderSelectionModeChange(isSelectionMode)
|
||||||
},
|
},
|
||||||
onSelectionCountChanged = { selectedCount ->
|
onSelectionCountChanged = { _ ->
|
||||||
updateEditButtonVisibility()
|
updateEditButtonVisibility()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
binding.recyclerView.adapter = listFolderAdapter
|
binding.recyclerView.adapter = listFolderAdapter
|
||||||
listFolderAdapter?.submitList(folders)
|
listFolderAdapter?.submitList(folders)
|
||||||
|
|
||||||
// Ensure proper icon state for folder view
|
|
||||||
if (listFolderAdapter?.isInSelectionMode() != true) {
|
if (listFolderAdapter?.isInSelectionMode() != true) {
|
||||||
showFolderViewIcons()
|
showFolderViewIcons()
|
||||||
}
|
}
|
||||||
@@ -312,10 +297,10 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
private fun refreshCurrentView() {
|
private fun refreshCurrentView() {
|
||||||
val isList = PrefsUtil(this).getBoolean("isList", false)
|
val isList = PrefsUtil(this).getBoolean("isList", false)
|
||||||
if (isList) {
|
if (isList) {
|
||||||
binding.folderOrientation.setImageResource(R.drawable.ic_grid)
|
binding.folderOrientation.setIconResource(R.drawable.ic_grid)
|
||||||
listFoldersInHiddenDirectoryListStyle()
|
listFoldersInHiddenDirectoryListStyle()
|
||||||
} else {
|
} else {
|
||||||
binding.folderOrientation.setImageResource(R.drawable.ic_list)
|
binding.folderOrientation.setIconResource(R.drawable.ic_list)
|
||||||
listFoldersInHiddenDirectory()
|
listFoldersInHiddenDirectory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,11 +329,11 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
override fun onNegativeButtonClicked() {
|
||||||
// Do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
override fun onNaturalButtonClicked() {
|
||||||
// Do nothing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -360,7 +345,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
selectedFolders.forEach { folder ->
|
selectedFolders.forEach { folder ->
|
||||||
if (!folderManager.deleteFolder(folder)) {
|
if (!folderManager.deleteFolder(folder)) {
|
||||||
allDeleted = false
|
allDeleted = false
|
||||||
Log.e(TAG, "Failed to delete folder: ${folder.name}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,26 +356,20 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Clear selection from both adapters
|
|
||||||
folderAdapter?.clearSelection()
|
folderAdapter?.clearSelection()
|
||||||
listFolderAdapter?.clearSelection()
|
listFolderAdapter?.clearSelection()
|
||||||
|
|
||||||
// This will trigger the selection mode change callback and show proper icons
|
|
||||||
exitFolderSelectionMode()
|
exitFolderSelectionMode()
|
||||||
|
|
||||||
// Refresh the current view based on orientation
|
|
||||||
refreshCurrentView()
|
refreshCurrentView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBackPress() {
|
private fun handleBackPress() {
|
||||||
|
|
||||||
|
|
||||||
// Check if folder adapters are in selection mode
|
|
||||||
if (folderAdapter?.onBackPressed() == true || listFolderAdapter?.onBackPressed() == true) {
|
if (folderAdapter?.onBackPressed() == true || listFolderAdapter?.onBackPressed() == true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle navigation back
|
|
||||||
if (currentFolder != null) {
|
if (currentFolder != null) {
|
||||||
navigateBackToFolders()
|
navigateBackToFolders()
|
||||||
} else {
|
} else {
|
||||||
@@ -402,25 +380,18 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
private fun navigateBackToFolders() {
|
private fun navigateBackToFolders() {
|
||||||
currentFolder = null
|
currentFolder = null
|
||||||
|
|
||||||
// Clean up file adapter
|
|
||||||
|
|
||||||
refreshCurrentView()
|
refreshCurrentView()
|
||||||
|
|
||||||
binding.folderName.text = getString(R.string.hidden_space)
|
binding.folderName.text = getString(R.string.hidden_space)
|
||||||
|
|
||||||
// Set proper icons for folder view
|
|
||||||
showFolderViewIcons()
|
showFolderViewIcons()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|
||||||
|
|
||||||
// Remove any pending callbacks
|
|
||||||
mainHandler.removeCallbacksAndMessages(null)
|
mainHandler.removeCallbacksAndMessages(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
//visibility related code
|
|
||||||
private fun showFolderViewIcons() {
|
private fun showFolderViewIcons() {
|
||||||
binding.folderOrientation.visibility = View.VISIBLE
|
binding.folderOrientation.visibility = View.VISIBLE
|
||||||
binding.settings.visibility = View.VISIBLE
|
binding.settings.visibility = View.VISIBLE
|
||||||
@@ -429,7 +400,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
binding.menuButton.visibility = View.GONE
|
binding.menuButton.visibility = View.GONE
|
||||||
binding.addFolder.visibility = View.VISIBLE
|
binding.addFolder.visibility = View.VISIBLE
|
||||||
binding.edit.visibility = View.GONE
|
binding.edit.visibility = View.GONE
|
||||||
// Ensure FABs are properly managed
|
|
||||||
if (currentFolder == null) {
|
if (currentFolder == null) {
|
||||||
|
|
||||||
binding.addFolder.visibility = View.VISIBLE
|
binding.addFolder.visibility = View.VISIBLE
|
||||||
@@ -442,8 +412,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
binding.deleteSelected.visibility = View.VISIBLE
|
binding.deleteSelected.visibility = View.VISIBLE
|
||||||
binding.menuButton.visibility = View.GONE
|
binding.menuButton.visibility = View.GONE
|
||||||
binding.addFolder.visibility = View.GONE
|
binding.addFolder.visibility = View.GONE
|
||||||
|
|
||||||
// Update edit button visibility based on current selection count
|
|
||||||
updateEditButtonVisibility()
|
updateEditButtonVisibility()
|
||||||
}
|
}
|
||||||
private fun exitFolderSelectionMode() {
|
private fun exitFolderSelectionMode() {
|
||||||
@@ -456,7 +424,6 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
enterFolderSelectionMode()
|
enterFolderSelectionMode()
|
||||||
}
|
}
|
||||||
// Always update edit button visibility when selection mode changes
|
|
||||||
updateEditButtonVisibility()
|
updateEditButtonVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,11 +487,8 @@ class HiddenActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (oldFolder.renameTo(newFolder)) {
|
if (oldFolder.renameTo(newFolder)) {
|
||||||
// Clear selection from both adapters
|
|
||||||
folderAdapter?.clearSelection()
|
folderAdapter?.clearSelection()
|
||||||
listFolderAdapter?.clearSelection()
|
listFolderAdapter?.clearSelection()
|
||||||
|
|
||||||
// Exit selection mode
|
|
||||||
exitFolderSelectionMode()
|
exitFolderSelectionMode()
|
||||||
|
|
||||||
refreshCurrentView()
|
refreshCurrentView()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.os.Bundle
|
|||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
@@ -22,6 +23,8 @@ import devs.org.calculator.utils.FileManager
|
|||||||
import devs.org.calculator.utils.PrefsUtil
|
import devs.org.calculator.utils.PrefsUtil
|
||||||
import net.objecthunter.exp4j.ExpressionBuilder
|
import net.objecthunter.exp4j.ExpressionBuilder
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.DialogCallback {
|
class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.DialogCallback {
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
@@ -34,13 +37,14 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
private val dialogUtil = DialogUtil(this)
|
private val dialogUtil = DialogUtil(this)
|
||||||
private val fileManager = FileManager(this, this)
|
private val fileManager = FileManager(this, this)
|
||||||
private val sp by lazy { getSharedPreferences("app", MODE_PRIVATE) }
|
private val sp by lazy { getSharedPreferences("app", MODE_PRIVATE) }
|
||||||
|
private val prefs:PrefsUtil by lazy { PrefsUtil(this) }
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
@RequiresApi(Build.VERSION_CODES.R)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
enableEdgeToEdge()
|
||||||
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
handleActivityResult(result)
|
handleActivityResult(result)
|
||||||
}
|
}
|
||||||
@@ -49,15 +53,14 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
binding.display.text = getString(R.string.enter_123456)
|
binding.display.text = getString(R.string.enter_123456)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask permission
|
|
||||||
if(!Environment.isExternalStorageManager()) {
|
if(!Environment.isExternalStorageManager()) {
|
||||||
dialogUtil.showMaterialDialog(
|
dialogUtil.showMaterialDialog(
|
||||||
"Storage Permission",
|
getString(R.string.storage_permission),
|
||||||
"To ensure the app works properly and allows you to easily hide or un-hide your private files, please grant storage access permission.\n" +
|
getString(R.string.to_ensure_the_app_works_properly_and_allows_you_to_easily_hide_or_un_hide_your_private_files_please_grant_storage_access_permission) +
|
||||||
"\n" +
|
"\n" +
|
||||||
"For devices running Android 11 or higher, you'll need to grant the 'All Files Access' permission.",
|
getString(R.string.for_devices_running_android_11_or_higher_you_ll_need_to_grant_the_all_files_access_permission),
|
||||||
"Grant",
|
getString(R.string.grant_permission),
|
||||||
"Later",
|
getString(R.string.later),
|
||||||
object : DialogUtil.DialogCallback {
|
object : DialogUtil.DialogCallback {
|
||||||
override fun onPositiveButtonClicked() {
|
override fun onPositiveButtonClicked() {
|
||||||
fileManager.askPermission(this@MainActivity)
|
fileManager.askPermission(this@MainActivity)
|
||||||
@@ -65,19 +68,20 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
override fun onNegativeButtonClicked() {
|
||||||
Toast.makeText(this@MainActivity,
|
Toast.makeText(this@MainActivity,
|
||||||
"Storage permission is required for the app to function properly",
|
getString(R.string.storage_permission_is_required_for_the_app_to_function_properly),
|
||||||
Toast.LENGTH_LONG).show()
|
Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
override fun onNaturalButtonClicked() {
|
||||||
Toast.makeText(this@MainActivity,
|
Toast.makeText(this@MainActivity,
|
||||||
"You can grant permission later from Settings",
|
getString(R.string.you_can_grant_permission_later_from_settings),
|
||||||
Toast.LENGTH_LONG).show()
|
Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
setupNumberButton(binding.btn0, "0")
|
setupNumberButton(binding.btn0, "0")
|
||||||
|
setupNumberButton(binding.btn00, "00")
|
||||||
setupNumberButton(binding.btn1, "1")
|
setupNumberButton(binding.btn1, "1")
|
||||||
setupNumberButton(binding.btn2, "2")
|
setupNumberButton(binding.btn2, "2")
|
||||||
setupNumberButton(binding.btn3, "3")
|
setupNumberButton(binding.btn3, "3")
|
||||||
@@ -99,6 +103,7 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
binding.cut.setOnClickListener { cutNumbers() }
|
binding.cut.setOnClickListener { cutNumbers() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun handleActivityResult(result: androidx.activity.result.ActivityResult) {
|
private fun handleActivityResult(result: androidx.activity.result.ActivityResult) {
|
||||||
if (result.resultCode == RESULT_OK) {
|
if (result.resultCode == RESULT_OK) {
|
||||||
result.data?.data?.let { uri ->
|
result.data?.data?.let { uri ->
|
||||||
@@ -107,10 +112,8 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
contentResolver.takePersistableUriPermission(uri, takeFlags)
|
contentResolver.takePersistableUriPermission(uri, takeFlags)
|
||||||
|
|
||||||
val preferences = getSharedPreferences("com.example.fileutility", MODE_PRIVATE)
|
val preferences = getSharedPreferences("com.example.fileutility", MODE_PRIVATE)
|
||||||
preferences.edit().putString("filestorageuri", uri.toString()).apply()
|
preferences.edit { putString("filestorageuri", uri.toString()) }
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Log.e("FileUtility", "Error occurred or operation cancelled: $result")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +152,7 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun clearDisplay() {
|
private fun clearDisplay() {
|
||||||
currentExpression = "0"
|
currentExpression = ""
|
||||||
binding.total.text = ""
|
binding.total.text = ""
|
||||||
lastWasOperator = false
|
lastWasOperator = false
|
||||||
lastWasPercent = false
|
lastWasPercent = false
|
||||||
@@ -173,41 +176,24 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculatePercentage() {
|
|
||||||
try {
|
|
||||||
val value = currentExpression.toDouble()
|
|
||||||
currentExpression = (value / 100).toString()
|
|
||||||
updateDisplay()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
binding.display.text = getString(R.string.invalid_message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun preprocessExpression(expression: String): String {
|
private fun preprocessExpression(expression: String): String {
|
||||||
val percentagePattern = Pattern.compile("(\\d+\\.?\\d*)%")
|
val percentagePattern = Pattern.compile("(\\d+\\.?\\d*)%")
|
||||||
val operatorPercentPattern = Pattern.compile("([+\\-*/])(\\d+\\.?\\d*)%")
|
val operatorPercentPattern = Pattern.compile("([+\\-*/])(\\d+\\.?\\d*)%")
|
||||||
|
|
||||||
var processedExpression = expression
|
var processedExpression = expression
|
||||||
|
|
||||||
// Replace standalone percentages (like "50%") with their decimal form (0.5)
|
|
||||||
val matcher = percentagePattern.matcher(processedExpression)
|
val matcher = percentagePattern.matcher(processedExpression)
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
val fullMatch = matcher.group(0)
|
val fullMatch = matcher.group(0)
|
||||||
val number = matcher.group(1)
|
val number = matcher.group(1)
|
||||||
|
|
||||||
// Check if it's a standalone percentage or part of an operation
|
|
||||||
val start = matcher.start()
|
val start = matcher.start()
|
||||||
if (start == 0 || !isOperator(processedExpression[start-1].toString())) {
|
if (start == 0 || !isOperator(processedExpression[start-1].toString())) {
|
||||||
val percentageValue = number.toDouble() / 100
|
val percentageValue = number!!.toDouble() / 100
|
||||||
processedExpression = processedExpression.replace(fullMatch, percentageValue.toString())
|
processedExpression = processedExpression.replace(fullMatch!!.toString(), percentageValue.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle operator-percentage combinations (like "100-20%")
|
|
||||||
val opMatcher = operatorPercentPattern.matcher(processedExpression)
|
val opMatcher = operatorPercentPattern.matcher(processedExpression)
|
||||||
val sb = StringBuilder(processedExpression)
|
val sb = StringBuilder(processedExpression)
|
||||||
|
|
||||||
// We need to process matches from right to left to maintain indices
|
|
||||||
val matches = mutableListOf<Triple<Int, Int, String>>()
|
val matches = mutableListOf<Triple<Int, Int, String>>()
|
||||||
|
|
||||||
while (opMatcher.find()) {
|
while (opMatcher.find()) {
|
||||||
@@ -219,15 +205,11 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
matches.add(Triple(start, end, "$operator$percentValue%"))
|
matches.add(Triple(start, end, "$operator$percentValue%"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process matches from right to left
|
|
||||||
for (match in matches.reversed()) {
|
for (match in matches.reversed()) {
|
||||||
val (start, end, fullMatch) = match
|
val (start, end, fullMatch) = match
|
||||||
|
|
||||||
// Find the number before this operator
|
|
||||||
var leftNumberEnd = start
|
|
||||||
var leftNumberStart = start - 1
|
var leftNumberStart = start - 1
|
||||||
|
|
||||||
// Skip parentheses and move to the actual number
|
|
||||||
if (leftNumberStart >= 0 && sb[leftNumberStart] == ')') {
|
if (leftNumberStart >= 0 && sb[leftNumberStart] == ')') {
|
||||||
var openParens = 1
|
var openParens = 1
|
||||||
leftNumberStart--
|
leftNumberStart--
|
||||||
@@ -238,7 +220,6 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
leftNumberStart--
|
leftNumberStart--
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we need to find the start of the expression
|
|
||||||
if (leftNumberStart >= 0) {
|
if (leftNumberStart >= 0) {
|
||||||
while (leftNumberStart >= 0 && (isDigit(sb[leftNumberStart].toString()) || sb[leftNumberStart] == '.' || sb[leftNumberStart] == '-')) {
|
while (leftNumberStart >= 0 && (isDigit(sb[leftNumberStart].toString()) || sb[leftNumberStart] == '.' || sb[leftNumberStart] == '-')) {
|
||||||
leftNumberStart--
|
leftNumberStart--
|
||||||
@@ -248,26 +229,24 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
leftNumberStart = 0
|
leftNumberStart = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For simple numbers, just find the start of the number
|
|
||||||
while (leftNumberStart >= 0 && (isDigit(sb[leftNumberStart].toString()) || sb[leftNumberStart] == '.')) {
|
while (leftNumberStart >= 0 && (isDigit(sb[leftNumberStart].toString()) || sb[leftNumberStart] == '.')) {
|
||||||
leftNumberStart--
|
leftNumberStart--
|
||||||
}
|
}
|
||||||
leftNumberStart++
|
leftNumberStart++
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftNumberStart < leftNumberEnd) {
|
if (leftNumberStart < start) {
|
||||||
val leftPart = sb.substring(leftNumberStart, leftNumberEnd)
|
val leftPart = sb.substring(leftNumberStart, start)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Extract the numerical values
|
|
||||||
val baseNumber = evaluateExpression(leftPart)
|
val baseNumber = evaluateExpression(leftPart)
|
||||||
val operator = fullMatch.substring(0, 1)
|
val operator = fullMatch.substring(0, 1)
|
||||||
val percentNumber = fullMatch.substring(1, fullMatch.length - 1).toDouble()
|
val percentNumber = fullMatch.substring(1, fullMatch.length - 1).toDouble()
|
||||||
|
|
||||||
// Calculate the percentage of the base number
|
|
||||||
val percentValue = baseNumber * (percentNumber / 100)
|
val percentValue = baseNumber * (percentNumber / 100)
|
||||||
|
|
||||||
// Calculate the new value based on the operator
|
|
||||||
val newValue = when (operator) {
|
val newValue = when (operator) {
|
||||||
"+" -> baseNumber + percentValue
|
"+" -> baseNumber + percentValue
|
||||||
"-" -> baseNumber - percentValue
|
"-" -> baseNumber - percentValue
|
||||||
@@ -276,7 +255,6 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
else -> baseNumber
|
else -> baseNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the entire expression "number operator percent%" with the result
|
|
||||||
sb.replace(leftNumberStart, end, newValue.toString())
|
sb.replace(leftNumberStart, end, newValue.toString())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("Calculator", "Error processing percentage expression: $e")
|
Log.e("Calculator", "Error processing percentage expression: $e")
|
||||||
@@ -303,10 +281,11 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
private fun calculateResult() {
|
private fun calculateResult() {
|
||||||
if (currentExpression == "123456") {
|
if (currentExpression == "123456") {
|
||||||
val intent = Intent(this, SetupPasswordActivity::class.java)
|
val intent = Intent(this, SetupPasswordActivity::class.java)
|
||||||
sp.edit().putBoolean("isFirst", false).apply()
|
sp.edit { putBoolean("isFirst", false) }
|
||||||
intent.putExtra("password", currentExpression)
|
intent.putExtra("password", currentExpression)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
clearDisplay()
|
clearDisplay()
|
||||||
@@ -363,8 +342,6 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
binding.total.text = ""
|
binding.total.text = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the expression for preview calculation
|
|
||||||
var processedExpression = currentExpression.replace("×", "*")
|
var processedExpression = currentExpression.replace("×", "*")
|
||||||
|
|
||||||
if (processedExpression.contains("%")) {
|
if (processedExpression.contains("%")) {
|
||||||
@@ -411,27 +388,24 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPositiveButtonClicked() {
|
override fun onPositiveButtonClicked() {
|
||||||
// Handle positive button click for both DialogUtil and DialogActionsCallback
|
|
||||||
fileManager.askPermission(this)
|
fileManager.askPermission(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
override fun onNegativeButtonClicked() {
|
||||||
// Handle negative button click
|
Toast.makeText(this, getString(R.string.storage_permission_is_required_for_the_app_to_function_properly), Toast.LENGTH_LONG).show()
|
||||||
Toast.makeText(this, "Storage permission is required for the app to function properly", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
override fun onNaturalButtonClicked() {
|
||||||
// Handle neutral button click
|
Toast.makeText(this, getString(R.string.you_can_grant_permission_later_from_settings), Toast.LENGTH_LONG).show()
|
||||||
Toast.makeText(this, "You can grant permission later from Settings", Toast.LENGTH_LONG).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
if (requestCode == 6767) {
|
if (requestCode == 6767) {
|
||||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, getString(R.string.permission_granted), Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, getString(R.string.permission_denied), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ import android.view.WindowManager
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
import devs.org.calculator.R
|
import devs.org.calculator.R
|
||||||
import devs.org.calculator.adapters.ImagePreviewAdapter
|
import devs.org.calculator.adapters.ImagePreviewAdapter
|
||||||
import devs.org.calculator.databinding.ActivityPreviewBinding
|
import devs.org.calculator.databinding.ActivityPreviewBinding
|
||||||
import devs.org.calculator.utils.DialogUtil
|
import devs.org.calculator.utils.DialogUtil
|
||||||
import devs.org.calculator.utils.FileManager
|
import devs.org.calculator.utils.FileManager
|
||||||
|
import devs.org.calculator.utils.PrefsUtil
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -18,43 +20,31 @@ class PreviewActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private lateinit var binding: ActivityPreviewBinding
|
private lateinit var binding: ActivityPreviewBinding
|
||||||
private var currentPosition: Int = 0
|
private var currentPosition: Int = 0
|
||||||
private lateinit var files: List<File>
|
private var files: MutableList<File> = mutableListOf()
|
||||||
private lateinit var type: String
|
private lateinit var type: String
|
||||||
private lateinit var folder: String
|
private lateinit var folder: String
|
||||||
private lateinit var filetype: FileManager.FileType
|
private lateinit var filetype: FileManager.FileType
|
||||||
private lateinit var adapter: ImagePreviewAdapter
|
private lateinit var adapter: ImagePreviewAdapter
|
||||||
private lateinit var fileManager: FileManager
|
private lateinit var fileManager: FileManager
|
||||||
private val dialogUtil = DialogUtil(this)
|
private val dialogUtil = DialogUtil(this)
|
||||||
|
private val prefs:PrefsUtil by lazy { PrefsUtil(this) }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityPreviewBinding.inflate(layoutInflater)
|
binding = ActivityPreviewBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
|
||||||
fileManager = FileManager(this, this)
|
fileManager = FileManager(this, this)
|
||||||
|
|
||||||
currentPosition = intent.getIntExtra("position", 0)
|
currentPosition = intent.getIntExtra("position", 0)
|
||||||
type = intent.getStringExtra("type").toString()
|
type = intent.getStringExtra("type") ?: "IMAGE"
|
||||||
folder = intent.getStringExtra("folder").toString()
|
folder = intent.getStringExtra("folder") ?: ""
|
||||||
|
|
||||||
setupFileType()
|
setupFileType()
|
||||||
files = fileManager.getFilesInHiddenDirFromFolder(filetype, folder = folder)
|
loadFiles()
|
||||||
|
|
||||||
setupImagePreview()
|
setupImagePreview()
|
||||||
clickListeners()
|
setupClickListeners()
|
||||||
|
setupPageChangeCallback()
|
||||||
binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
|
||||||
override fun onPageSelected(position: Int) {
|
|
||||||
super.onPageSelected(position)
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
binding.back.setOnClickListener {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -62,6 +52,16 @@ class PreviewActivity : AppCompatActivity() {
|
|||||||
setupFlagSecure()
|
setupFlagSecure()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
adapter.releaseAllResources()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
adapter.releaseAllResources()
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupFlagSecure() {
|
private fun setupFlagSecure() {
|
||||||
val prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
val prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
||||||
if (prefs.getBoolean("screenshot_restriction", true)) {
|
if (prefs.getBoolean("screenshot_restriction", true)) {
|
||||||
@@ -93,108 +93,162 @@ class PreviewActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadFiles() {
|
||||||
|
try {
|
||||||
|
val filesList = fileManager.getFilesInHiddenDirFromFolder(filetype, folder = folder)
|
||||||
|
files = filesList.toMutableList()
|
||||||
|
|
||||||
|
if (currentPosition >= files.size) {
|
||||||
|
currentPosition = 0
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
files = mutableListOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupImagePreview() {
|
private fun setupImagePreview() {
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
adapter = ImagePreviewAdapter(this, this)
|
adapter = ImagePreviewAdapter(this, this)
|
||||||
adapter.images = files
|
adapter.images = files
|
||||||
binding.viewPager.adapter = adapter
|
binding.viewPager.adapter = adapter
|
||||||
|
if (currentPosition < files.size) {
|
||||||
binding.viewPager.setCurrentItem(currentPosition, false)
|
binding.viewPager.setCurrentItem(currentPosition, false)
|
||||||
|
|
||||||
val fileUri = Uri.fromFile(files[currentPosition])
|
|
||||||
val fileName = FileManager.FileName(this).getFileNameFromUri(fileUri).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
if (filetype == FileManager.FileType.AUDIO) {
|
|
||||||
(binding.viewPager.adapter as? ImagePreviewAdapter)?.currentMediaPlayer?.pause()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFileInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
private fun setupPageChangeCallback() {
|
||||||
super.onDestroy()
|
binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||||
if (filetype == FileManager.FileType.AUDIO) {
|
override fun onPageSelected(position: Int) {
|
||||||
(binding.viewPager.adapter as? ImagePreviewAdapter)?.let { adapter ->
|
super.onPageSelected(position)
|
||||||
adapter.currentMediaPlayer?.release()
|
currentPosition = position
|
||||||
adapter.currentMediaPlayer = null
|
updateFileInfo()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateFileInfo() {
|
||||||
|
if (files.isNotEmpty() && currentPosition < files.size) {
|
||||||
|
val fileUri = Uri.fromFile(files[currentPosition])
|
||||||
|
val fileName = FileManager.FileName(this).getFileNameFromUri(fileUri) ?: "Unknown"
|
||||||
|
//For Now File Name not Needed, i am keeping it for later use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun clickListeners() {
|
|
||||||
|
private fun setupClickListeners() {
|
||||||
|
binding.back.setOnClickListener {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
binding.delete.setOnClickListener {
|
binding.delete.setOnClickListener {
|
||||||
val fileUri = FileManager.FileManager().getContentUriImage(this, files[binding.viewPager.currentItem])
|
handleDeleteFile()
|
||||||
if (fileUri != null) {
|
|
||||||
dialogUtil.showMaterialDialog(
|
|
||||||
getString(R.string.delete_file),
|
|
||||||
getString(R.string.are_you_sure_to_delete_this_file_permanently),
|
|
||||||
getString(R.string.delete_permanently),
|
|
||||||
getString(R.string.cancel),
|
|
||||||
object : DialogUtil.DialogCallback {
|
|
||||||
override fun onPositiveButtonClicked() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
FileManager(this@PreviewActivity, this@PreviewActivity).deletePhotoFromExternalStorage(fileUri)
|
|
||||||
removeFileFromList(binding.viewPager.currentItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
|
||||||
// Handle negative button click
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
|
||||||
// Handle neutral button click
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.unHide.setOnClickListener {
|
binding.unHide.setOnClickListener {
|
||||||
val fileUri = FileManager.FileManager().getContentUriImage(this, files[binding.viewPager.currentItem])
|
handleUnhideFile()
|
||||||
if (fileUri != null) {
|
}
|
||||||
dialogUtil.showMaterialDialog(
|
binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||||
getString(R.string.un_hide_file),
|
override fun onPageSelected(position: Int) {
|
||||||
getString(R.string.are_you_sure_you_want_to_un_hide_this_file),
|
super.onPageSelected(position)
|
||||||
getString(R.string.un_hide),
|
adapter.onItemScrolledAway(currentPosition)
|
||||||
getString(R.string.cancel),
|
currentPosition = position
|
||||||
object : DialogUtil.DialogCallback {
|
}
|
||||||
override fun onPositiveButtonClicked() {
|
})
|
||||||
lifecycleScope.launch {
|
}
|
||||||
FileManager(this@PreviewActivity, this@PreviewActivity).copyFileToNormalDir(fileUri)
|
|
||||||
removeFileFromList(binding.viewPager.currentItem)
|
private fun handleDeleteFile() {
|
||||||
|
if (files.isEmpty() || currentPosition >= files.size) return
|
||||||
|
|
||||||
|
val currentFile = files[currentPosition]
|
||||||
|
val fileUri = FileManager.FileManager().getContentUriImage(this, currentFile)
|
||||||
|
|
||||||
|
if (fileUri != null) {
|
||||||
|
dialogUtil.showMaterialDialog(
|
||||||
|
getString(R.string.delete_file),
|
||||||
|
getString(R.string.are_you_sure_to_delete_this_file_permanently),
|
||||||
|
getString(R.string.delete_permanently),
|
||||||
|
getString(R.string.cancel),
|
||||||
|
object : DialogUtil.DialogCallback {
|
||||||
|
override fun onPositiveButtonClicked() {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
try {
|
||||||
|
fileManager.deletePhotoFromExternalStorage(fileUri)
|
||||||
|
removeFileFromList(currentPosition)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
override fun onNegativeButtonClicked() {}
|
||||||
// Handle negative button click
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
override fun onNaturalButtonClicked() {}
|
||||||
// Handle neutral button click
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleUnhideFile() {
|
||||||
|
if (files.isEmpty() || currentPosition >= files.size) return
|
||||||
|
|
||||||
|
val currentFile = files[currentPosition]
|
||||||
|
val fileUri = FileManager.FileManager().getContentUriImage(this, currentFile)
|
||||||
|
|
||||||
|
if (fileUri != null) {
|
||||||
|
dialogUtil.showMaterialDialog(
|
||||||
|
getString(R.string.un_hide_file),
|
||||||
|
getString(R.string.are_you_sure_you_want_to_un_hide_this_file),
|
||||||
|
getString(R.string.un_hide),
|
||||||
|
getString(R.string.cancel),
|
||||||
|
object : DialogUtil.DialogCallback {
|
||||||
|
override fun onPositiveButtonClicked() {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
try {
|
||||||
|
fileManager.copyFileToNormalDir(fileUri)
|
||||||
|
removeFileFromList(currentPosition)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
override fun onNegativeButtonClicked() {}
|
||||||
|
|
||||||
|
override fun onNaturalButtonClicked() {}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeFileFromList(position: Int) {
|
private fun removeFileFromList(position: Int) {
|
||||||
val updatedFiles = files.toMutableList().apply { removeAt(position) }
|
if (position < 0 || position >= files.size) return
|
||||||
files = updatedFiles
|
adapter.releaseAllResources()
|
||||||
adapter.images = updatedFiles // Update adapter with the new list
|
files.removeAt(position)
|
||||||
|
adapter.images = files
|
||||||
// Update the ViewPager's position
|
if (files.isEmpty()) {
|
||||||
if (updatedFiles.isEmpty()) finish()
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentPosition = if (position >= files.size) {
|
||||||
|
files.size - 1
|
||||||
|
} else {
|
||||||
|
position
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.viewPager.setCurrentItem(currentPosition, false)
|
||||||
|
updateFileInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportNavigateUp(): Boolean {
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
onBackPressed()
|
finish()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,36 +1,32 @@
|
|||||||
package devs.org.calculator.activities
|
package devs.org.calculator.activities
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.WindowCompat
|
import com.google.android.material.color.DynamicColors
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import devs.org.calculator.R
|
import devs.org.calculator.R
|
||||||
import devs.org.calculator.databinding.ActivitySettingsBinding
|
import devs.org.calculator.databinding.ActivitySettingsBinding
|
||||||
|
import devs.org.calculator.utils.PrefsUtil
|
||||||
|
|
||||||
class SettingsActivity : AppCompatActivity() {
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var binding: ActivitySettingsBinding
|
private lateinit var binding: ActivitySettingsBinding
|
||||||
private lateinit var prefs: SharedPreferences
|
private val prefs:PrefsUtil by lazy { PrefsUtil(this) }
|
||||||
private val DEV_GITHUB_URL = "https://github.com/binondi"
|
private var DEV_GITHUB_URL = ""
|
||||||
private val GITHUB_URL = "$DEV_GITHUB_URL/calculator-hide-files"
|
private var GITHUB_URL = ""
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
DEV_GITHUB_URL = getString(R.string.github_profile)
|
||||||
prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
GITHUB_URL = getString(R.string.calculator_hide_files, DEV_GITHUB_URL)
|
||||||
setupUI()
|
setupUI()
|
||||||
loadSettings()
|
loadSettings()
|
||||||
setupListeners()
|
setupListeners()
|
||||||
@@ -42,6 +38,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun loadSettings() {
|
private fun loadSettings() {
|
||||||
|
|
||||||
binding.dynamicThemeSwitch.isChecked = prefs.getBoolean("dynamic_theme", true)
|
binding.dynamicThemeSwitch.isChecked = prefs.getBoolean("dynamic_theme", true)
|
||||||
@@ -72,9 +69,14 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.dynamicThemeSwitch.setOnCheckedChangeListener { _, isChecked ->
|
binding.dynamicThemeSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
prefs.edit().putBoolean("dynamic_theme", isChecked).apply()
|
prefs.setBoolean("dynamic_theme", isChecked)
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
showThemeModeDialog()
|
showThemeModeDialog()
|
||||||
|
}else{
|
||||||
|
showThemeModeDialog()
|
||||||
|
if (!prefs.getBoolean("isAppReopened",false)){
|
||||||
|
DynamicColors.applyToActivityIfAvailable(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +99,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.screenshotRestrictionSwitch.setOnCheckedChangeListener { _, isChecked ->
|
binding.screenshotRestrictionSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
prefs.edit().putBoolean("screenshot_restriction", isChecked).apply()
|
prefs.setBoolean("screenshot_restriction", isChecked)
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
enableScreenshotRestriction()
|
enableScreenshotRestriction()
|
||||||
} else {
|
} else {
|
||||||
@@ -105,7 +107,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.showFileNames.setOnCheckedChangeListener { _, isChecked ->
|
binding.showFileNames.setOnCheckedChangeListener { _, isChecked ->
|
||||||
prefs.edit().putBoolean("showFileName", isChecked).apply()
|
prefs.setBoolean("showFileName", isChecked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,20 +117,16 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun showThemeModeDialog() {
|
private fun showThemeModeDialog() {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle("Theme Mode")
|
.setTitle(getString(R.string.attention))
|
||||||
.setMessage("Would you like to set a specific theme mode?")
|
.setMessage(getString(R.string.if_you_turn_on_off_this_option_dynamic_theme_changes_will_be_visible_after_you_reopen_the_app))
|
||||||
.setPositiveButton("Yes") { _, _ ->
|
.setPositiveButton(getString(R.string.ok)) { _, _ ->
|
||||||
binding.themeModeSwitch.isChecked = true
|
|
||||||
}
|
|
||||||
.setNegativeButton("No") { _, _ ->
|
|
||||||
binding.systemThemeRadio.isChecked = true
|
|
||||||
applyThemeMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyThemeMode(themeMode: Int) {
|
private fun applyThemeMode(themeMode: Int) {
|
||||||
prefs.edit().putInt("theme_mode", themeMode).apply()
|
prefs.setInt("theme_mode", themeMode)
|
||||||
AppCompatDelegate.setDefaultNightMode(themeMode)
|
AppCompatDelegate.setDefaultNightMode(themeMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,10 +143,11 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun openUrl(url: String) {
|
private fun openUrl(url: String) {
|
||||||
try {
|
try {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Snackbar.make(binding.root, "Could not open URL", Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(binding.root,
|
||||||
|
getString(R.string.could_not_open_url), Snackbar.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import android.view.LayoutInflater
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import devs.org.calculator.databinding.ActivitySetupPasswordBinding
|
import devs.org.calculator.databinding.ActivitySetupPasswordBinding
|
||||||
@@ -18,6 +19,7 @@ class SetupPasswordActivity : AppCompatActivity() {
|
|||||||
private lateinit var binding2: ActivityChangePasswordBinding
|
private lateinit var binding2: ActivityChangePasswordBinding
|
||||||
private lateinit var prefsUtil: PrefsUtil
|
private lateinit var prefsUtil: PrefsUtil
|
||||||
private var hasPassword = false
|
private var hasPassword = false
|
||||||
|
private val prefs:PrefsUtil by lazy { PrefsUtil(this) }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -72,8 +74,6 @@ class SetupPasswordActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.btnResetPassword.setOnClickListener {
|
binding.btnResetPassword.setOnClickListener {
|
||||||
// Implement password reset logic
|
|
||||||
// Could use security questions or email verification
|
|
||||||
if (prefsUtil.getSecurityQuestion() != null) showSecurityQuestionDialog(prefsUtil.getSecurityQuestion().toString())
|
if (prefsUtil.getSecurityQuestion() != null) showSecurityQuestionDialog(prefsUtil.getSecurityQuestion().toString())
|
||||||
else Toast.makeText(this,
|
else Toast.makeText(this,
|
||||||
getString(R.string.security_question_not_set_yet), Toast.LENGTH_SHORT).show()
|
getString(R.string.security_question_not_set_yet), Toast.LENGTH_SHORT).show()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package devs.org.calculator.activities
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
@@ -20,8 +19,9 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import devs.org.calculator.R
|
import devs.org.calculator.R
|
||||||
import devs.org.calculator.adapters.FileAdapter
|
import devs.org.calculator.adapters.FileAdapter
|
||||||
import devs.org.calculator.adapters.FolderSelectionAdapter
|
import devs.org.calculator.adapters.FolderSelectionAdapter
|
||||||
@@ -32,6 +32,7 @@ import devs.org.calculator.utils.DialogUtil
|
|||||||
import devs.org.calculator.utils.FileManager
|
import devs.org.calculator.utils.FileManager
|
||||||
import devs.org.calculator.utils.FileManager.Companion.HIDDEN_DIR
|
import devs.org.calculator.utils.FileManager.Companion.HIDDEN_DIR
|
||||||
import devs.org.calculator.utils.FolderManager
|
import devs.org.calculator.utils.FolderManager
|
||||||
|
import devs.org.calculator.utils.PrefsUtil
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -51,12 +52,12 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
private var currentFolder: File? = null
|
private var currentFolder: File? = null
|
||||||
private val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
private val hiddenDir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR)
|
||||||
private lateinit var pickImageLauncher: ActivityResultLauncher<Intent>
|
private lateinit var pickImageLauncher: ActivityResultLauncher<Intent>
|
||||||
private lateinit var prefs: SharedPreferences
|
|
||||||
|
|
||||||
private var customDialog: androidx.appcompat.app.AlertDialog? = null
|
private var customDialog: androidx.appcompat.app.AlertDialog? = null
|
||||||
|
|
||||||
private var dialogShowTime: Long = 0
|
private var dialogShowTime: Long = 0
|
||||||
private val MINIMUM_DIALOG_DURATION = 1200L
|
private val MINIMUM_DIALOG_DURATION = 1200L
|
||||||
|
private val prefs:PrefsUtil by lazy { PrefsUtil(this) }
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -81,11 +82,11 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
fileManager = FileManager(this, this)
|
fileManager = FileManager(this, this)
|
||||||
folderManager = FolderManager(this)
|
folderManager = FolderManager()
|
||||||
dialogUtil = DialogUtil(this)
|
dialogUtil = DialogUtil(this)
|
||||||
prefs = getSharedPreferences("app_settings", MODE_PRIVATE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun setupActivityResultLaunchers() {
|
private fun setupActivityResultLaunchers() {
|
||||||
pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
if (result.resultCode == RESULT_OK) {
|
if (result.resultCode == RESULT_OK) {
|
||||||
@@ -192,19 +193,12 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshCurrentView() {
|
|
||||||
if (currentFolder != null) {
|
|
||||||
refreshCurrentFolder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
refreshCurrentFolder()
|
refreshCurrentFolder()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openFolder(folder: File) {
|
private fun openFolder(folder: File) {
|
||||||
// Ensure folder exists and has .nomedia file
|
|
||||||
if (!folder.exists()) {
|
if (!folder.exists()) {
|
||||||
folder.mkdirs()
|
folder.mkdirs()
|
||||||
File(folder, ".nomedia").createNewFile()
|
File(folder, ".nomedia").createNewFile()
|
||||||
@@ -227,8 +221,6 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun showFileList(files: List<File>, folder: File) {
|
private fun showFileList(files: List<File>, folder: File) {
|
||||||
binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
|
binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
|
||||||
|
|
||||||
// Clean up previous adapter
|
|
||||||
fileAdapter?.cleanup()
|
fileAdapter?.cleanup()
|
||||||
|
|
||||||
fileAdapter = FileAdapter(this, this, folder, prefs.getBoolean("showFileName", true),
|
fileAdapter = FileAdapter(this, this, folder, prefs.getBoolean("showFileName", true),
|
||||||
@@ -344,13 +336,9 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
performFileUnhiding(selectedFiles)
|
performFileUnhiding(selectedFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
override fun onNegativeButtonClicked() {}
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
override fun onNaturalButtonClicked() {}
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -368,13 +356,9 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
performFileDeletion(selectedFiles)
|
performFileDeletion(selectedFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNegativeButtonClicked() {
|
override fun onNegativeButtonClicked() {}
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNaturalButtonClicked() {
|
override fun onNaturalButtonClicked() {}
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -523,8 +507,6 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(this@ViewFolderActivity, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@ViewFolderActivity, message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Fixed: Ensure proper order of operations
|
|
||||||
fileAdapter?.exitSelectionMode()
|
fileAdapter?.exitSelectionMode()
|
||||||
refreshCurrentFolder()
|
refreshCurrentFolder()
|
||||||
}
|
}
|
||||||
@@ -546,8 +528,6 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Fixed: Ensure proper order of operations
|
|
||||||
fileAdapter?.exitSelectionMode()
|
fileAdapter?.exitSelectionMode()
|
||||||
refreshCurrentFolder()
|
refreshCurrentFolder()
|
||||||
}
|
}
|
||||||
@@ -569,10 +549,8 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val message = if (allCopied) "Files copied successfully" else "Some files could not be copied"
|
val message = if (allCopied) getString(R.string.files_copied_successfully) else getString(R.string.some_files_could_not_be_copied)
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Fixed: Ensure proper order of operations
|
|
||||||
fileAdapter?.exitSelectionMode()
|
fileAdapter?.exitSelectionMode()
|
||||||
refreshCurrentFolder()
|
refreshCurrentFolder()
|
||||||
}
|
}
|
||||||
@@ -589,17 +567,15 @@ class ViewFolderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val message = if (allMoved) "Files moved successfully" else "Some files could not be moved"
|
val message = if (allMoved) getString(R.string.files_moved_successfully) else getString(R.string.some_files_could_not_be_moved)
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Fixed: Ensure proper order of operations
|
|
||||||
fileAdapter?.exitSelectionMode()
|
fileAdapter?.exitSelectionMode()
|
||||||
refreshCurrentFolder()
|
refreshCurrentFolder()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showFolderSelectionDialog(onFolderSelected: (File) -> Unit) {
|
private fun showFolderSelectionDialog(onFolderSelected: (File) -> Unit) {
|
||||||
val folders = folderManager.getFoldersInDirectory(hiddenDir)
|
val folders = folderManager.getFoldersInDirectory(hiddenDir)
|
||||||
.filter { it != currentFolder } // Exclude current folder
|
.filter { it != currentFolder }
|
||||||
|
|
||||||
if (folders.isEmpty()) {
|
if (folders.isEmpty()) {
|
||||||
Toast.makeText(this, getString(R.string.no_folders_available), Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, getString(R.string.no_folders_available), Toast.LENGTH_SHORT).show()
|
||||||
|
|||||||
@@ -38,10 +38,8 @@ class FileAdapter(
|
|||||||
private val selectedItems = mutableSetOf<Int>()
|
private val selectedItems = mutableSetOf<Int>()
|
||||||
private var isSelectionMode = false
|
private var isSelectionMode = false
|
||||||
|
|
||||||
// Use WeakReference to prevent memory leaks
|
|
||||||
private var fileOperationCallback: WeakReference<FileOperationCallback>? = null
|
private var fileOperationCallback: WeakReference<FileOperationCallback>? = null
|
||||||
|
|
||||||
// Background executor for file operations
|
|
||||||
private val fileExecutor = Executors.newSingleThreadExecutor()
|
private val fileExecutor = Executors.newSingleThreadExecutor()
|
||||||
private val mainHandler = Handler(Looper.getMainLooper())
|
private val mainHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
@@ -49,7 +47,6 @@ class FileAdapter(
|
|||||||
private const val TAG = "FileAdapter"
|
private const val TAG = "FileAdapter"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback interface for handling file operations and selection changes
|
|
||||||
interface FileOperationCallback {
|
interface FileOperationCallback {
|
||||||
fun onFileDeleted(file: File)
|
fun onFileDeleted(file: File)
|
||||||
fun onFileRenamed(oldFile: File, newFile: File)
|
fun onFileRenamed(oldFile: File, newFile: File)
|
||||||
@@ -75,7 +72,6 @@ class FileAdapter(
|
|||||||
setupClickListeners(file, fileType)
|
setupClickListeners(file, fileType)
|
||||||
fileNameTextView.visibility = if (showFileName) View.VISIBLE else View.GONE
|
fileNameTextView.visibility = if (showFileName) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
// Update selection state
|
|
||||||
val position = adapterPosition
|
val position = adapterPosition
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
val isSelected = selectedItems.contains(position)
|
val isSelected = selectedItems.contains(position)
|
||||||
@@ -89,7 +85,6 @@ class FileAdapter(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle partial updates based on payload
|
|
||||||
val changes = payloads.firstOrNull() as? List<String>
|
val changes = payloads.firstOrNull() as? List<String>
|
||||||
changes?.forEach { change ->
|
changes?.forEach { change ->
|
||||||
when (change) {
|
when (change) {
|
||||||
@@ -97,14 +92,13 @@ class FileAdapter(
|
|||||||
fileNameTextView.text = file.name
|
fileNameTextView.text = file.name
|
||||||
}
|
}
|
||||||
"SIZE_CHANGED", "MODIFIED_DATE_CHANGED" -> {
|
"SIZE_CHANGED", "MODIFIED_DATE_CHANGED" -> {
|
||||||
// Could update file info if displayed
|
|
||||||
}
|
}
|
||||||
"SELECTION_CHANGED" -> {
|
"SELECTION_CHANGED" -> {
|
||||||
val position = adapterPosition
|
val position = adapterPosition
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
val isSelected = selectedItems.contains(position)
|
val isSelected = selectedItems.contains(position)
|
||||||
updateSelectionUI(isSelected)
|
updateSelectionUI(isSelected)
|
||||||
// Notify activity about selection change
|
|
||||||
notifySelectionModeChange()
|
notifySelectionModeChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +122,6 @@ class FileAdapter(
|
|||||||
.centerCrop()
|
.centerCrop()
|
||||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
.error(R.drawable.ic_document)
|
.error(R.drawable.ic_document)
|
||||||
.placeholder(R.drawable.ic_document)
|
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
}
|
}
|
||||||
FileManager.FileType.VIDEO -> {
|
FileManager.FileType.VIDEO -> {
|
||||||
@@ -138,12 +131,12 @@ class FileAdapter(
|
|||||||
.centerCrop()
|
.centerCrop()
|
||||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||||
.error(R.drawable.ic_document)
|
.error(R.drawable.ic_document)
|
||||||
.placeholder(R.drawable.ic_document)
|
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
}
|
}
|
||||||
FileManager.FileType.AUDIO -> {
|
FileManager.FileType.AUDIO -> {
|
||||||
playIcon.visibility = View.GONE
|
playIcon.visibility = View.GONE
|
||||||
imageView.setImageResource(R.drawable.ic_audio)
|
imageView.setImageResource(R.drawable.ic_audio)
|
||||||
|
imageView.setPadding(50,50,50,50)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
playIcon.visibility = View.GONE
|
playIcon.visibility = View.GONE
|
||||||
@@ -191,16 +184,18 @@ class FileAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun openAudioFile(file: File) {
|
private fun openAudioFile(file: File) {
|
||||||
|
val fileType = FileManager(context,lifecycleOwner).getFileType(file)
|
||||||
try {
|
try {
|
||||||
val uri = FileProvider.getUriForFile(
|
val fileTypeString = when (fileType) {
|
||||||
context,
|
FileManager.FileType.IMAGE -> context.getString(R.string.image)
|
||||||
"${context.packageName}.fileprovider",
|
FileManager.FileType.VIDEO -> context.getString(R.string.video)
|
||||||
file
|
else -> "unknown"
|
||||||
)
|
}
|
||||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
|
||||||
setDataAndType(uri, "audio/*")
|
val intent = Intent(context, PreviewActivity::class.java).apply {
|
||||||
|
putExtra("type", fileTypeString)
|
||||||
putExtra("folder", currentFolder.toString())
|
putExtra("folder", currentFolder.toString())
|
||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
putExtra("position", adapterPosition)
|
||||||
}
|
}
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -316,7 +311,6 @@ class FileAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteFile(file: File) {
|
private fun deleteFile(file: File) {
|
||||||
// Show confirmation dialog first
|
|
||||||
MaterialAlertDialogBuilder(context)
|
MaterialAlertDialogBuilder(context)
|
||||||
.setTitle("Delete File")
|
.setTitle("Delete File")
|
||||||
.setMessage("Are you sure you want to delete ${file.name}?")
|
.setMessage("Are you sure you want to delete ${file.name}?")
|
||||||
@@ -436,12 +430,10 @@ class FileAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun copyToAnotherFolder(file: File) {
|
private fun copyToAnotherFolder(file: File) {
|
||||||
// This will be handled by the activity
|
|
||||||
fileOperationCallback?.get()?.onRefreshNeeded()
|
fileOperationCallback?.get()?.onRefreshNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moveToAnotherFolder(file: File) {
|
private fun moveToAnotherFolder(file: File) {
|
||||||
// This will be handled by the activity
|
|
||||||
fileOperationCallback?.get()?.onRefreshNeeded()
|
fileOperationCallback?.get()?.onRefreshNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +481,6 @@ class FileAdapter(
|
|||||||
currentList.clear()
|
currentList.clear()
|
||||||
super.submitList(null)
|
super.submitList(null)
|
||||||
} else {
|
} else {
|
||||||
// Create a new list to force update
|
|
||||||
val newList = list.toMutableList()
|
val newList = list.toMutableList()
|
||||||
super.submitList(newList)
|
super.submitList(newList)
|
||||||
}
|
}
|
||||||
@@ -502,6 +493,7 @@ class FileAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun exitSelectionMode() {
|
fun exitSelectionMode() {
|
||||||
if (isSelectionMode) {
|
if (isSelectionMode) {
|
||||||
isSelectionMode = false
|
isSelectionMode = false
|
||||||
@@ -574,8 +566,6 @@ class FileAdapter(
|
|||||||
fun deleteSelectedFiles() {
|
fun deleteSelectedFiles() {
|
||||||
val selectedFiles = getSelectedItems()
|
val selectedFiles = getSelectedItems()
|
||||||
if (selectedFiles.isEmpty()) return
|
if (selectedFiles.isEmpty()) return
|
||||||
|
|
||||||
// Show confirmation dialog
|
|
||||||
MaterialAlertDialogBuilder(context)
|
MaterialAlertDialogBuilder(context)
|
||||||
.setTitle("Delete Files")
|
.setTitle("Delete Files")
|
||||||
.setMessage("Are you sure you want to delete ${selectedFiles.size} file(s)?")
|
.setMessage("Are you sure you want to delete ${selectedFiles.size} file(s)?")
|
||||||
@@ -611,10 +601,8 @@ class FileAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainHandler.post {
|
mainHandler.post {
|
||||||
// Exit selection mode first
|
|
||||||
exitSelectionMode()
|
exitSelectionMode()
|
||||||
|
|
||||||
// Show detailed result message
|
|
||||||
when {
|
when {
|
||||||
deletedCount > 0 && failedCount == 0 -> {
|
deletedCount > 0 && failedCount == 0 -> {
|
||||||
Toast.makeText(context, "Deleted $deletedCount file(s)", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Deleted $deletedCount file(s)", Toast.LENGTH_SHORT).show()
|
||||||
@@ -641,7 +629,6 @@ class FileAdapter(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (selectedFiles.size == 1) {
|
if (selectedFiles.size == 1) {
|
||||||
// Share single file
|
|
||||||
val file = selectedFiles.first()
|
val file = selectedFiles.first()
|
||||||
val uri = FileProvider.getUriForFile(
|
val uri = FileProvider.getUriForFile(
|
||||||
context,
|
context,
|
||||||
@@ -657,7 +644,6 @@ class FileAdapter(
|
|||||||
Intent.createChooser(shareIntent, context.getString(R.string.share_file))
|
Intent.createChooser(shareIntent, context.getString(R.string.share_file))
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Share multiple files
|
|
||||||
val uris = selectedFiles.mapNotNull { file ->
|
val uris = selectedFiles.mapNotNull { file ->
|
||||||
try {
|
try {
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
@@ -709,7 +695,6 @@ class FileAdapter(
|
|||||||
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
notifyItemChanged(position, listOf("SELECTION_CHANGED"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ensure callback is notified
|
|
||||||
notifySelectionModeChange()
|
notifySelectionModeChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,10 @@ import java.io.File
|
|||||||
class FileDiffCallback : DiffUtil.ItemCallback<File>() {
|
class FileDiffCallback : DiffUtil.ItemCallback<File>() {
|
||||||
|
|
||||||
override fun areItemsTheSame(oldItem: File, newItem: File): Boolean {
|
override fun areItemsTheSame(oldItem: File, newItem: File): Boolean {
|
||||||
// Compare by absolute path since File objects might be different instances
|
|
||||||
// but represent the same file
|
|
||||||
return oldItem.absolutePath == newItem.absolutePath
|
return oldItem.absolutePath == newItem.absolutePath
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: File, newItem: File): Boolean {
|
override fun areContentsTheSame(oldItem: File, newItem: File): Boolean {
|
||||||
// Compare all relevant properties that might change and affect the UI
|
|
||||||
return oldItem.name == newItem.name &&
|
return oldItem.name == newItem.name &&
|
||||||
oldItem.length() == newItem.length() &&
|
oldItem.length() == newItem.length() &&
|
||||||
oldItem.lastModified() == newItem.lastModified() &&
|
oldItem.lastModified() == newItem.lastModified() &&
|
||||||
@@ -22,8 +19,6 @@ class FileDiffCallback : DiffUtil.ItemCallback<File>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getChangePayload(oldItem: File, newItem: File): Any? {
|
override fun getChangePayload(oldItem: File, newItem: File): Any? {
|
||||||
// Return a payload if only specific properties changed
|
|
||||||
// This allows for partial updates instead of full rebinding
|
|
||||||
val changes = mutableListOf<String>()
|
val changes = mutableListOf<String>()
|
||||||
|
|
||||||
if (oldItem.name != newItem.name) {
|
if (oldItem.name != newItem.name) {
|
||||||
@@ -42,6 +37,6 @@ class FileDiffCallback : DiffUtil.ItemCallback<File>() {
|
|||||||
changes.add("EXISTENCE_CHANGED")
|
changes.add("EXISTENCE_CHANGED")
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (changes.isNotEmpty()) changes else null
|
return changes.ifEmpty { null }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package devs.org.calculator.adapters
|
package devs.org.calculator.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -80,6 +81,7 @@ class FolderAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun clearSelection() {
|
fun clearSelection() {
|
||||||
val wasInSelectionMode = isSelectionMode
|
val wasInSelectionMode = isSelectionMode
|
||||||
selectedItems.clear()
|
selectedItems.clear()
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.MediaController
|
import android.widget.MediaController
|
||||||
import android.widget.SeekBar
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.recyclerview.widget.AsyncListDiffer
|
import androidx.recyclerview.widget.AsyncListDiffer
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@@ -25,11 +24,8 @@ class ImagePreviewAdapter(
|
|||||||
) : RecyclerView.Adapter<ImagePreviewAdapter.ImageViewHolder>() {
|
) : RecyclerView.Adapter<ImagePreviewAdapter.ImageViewHolder>() {
|
||||||
|
|
||||||
private val differ = AsyncListDiffer(this, FileDiffCallback())
|
private val differ = AsyncListDiffer(this, FileDiffCallback())
|
||||||
var currentMediaPlayer: MediaPlayer? = null
|
|
||||||
var isMediaPlayerPrepared = false
|
|
||||||
var currentViewHolder: ImageViewHolder? = null
|
|
||||||
private var currentPlayingPosition = -1
|
private var currentPlayingPosition = -1
|
||||||
private var isPlaying = false
|
private var currentViewHolder: ImageViewHolder? = null
|
||||||
|
|
||||||
var images: List<File>
|
var images: List<File>
|
||||||
get() = differ.currentList
|
get() = differ.currentList
|
||||||
@@ -43,32 +39,35 @@ class ImagePreviewAdapter(
|
|||||||
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
|
||||||
val imageUrl = images[position]
|
val imageUrl = images[position]
|
||||||
val fileType = FileManager(context, lifecycleOwner).getFileType(images[position])
|
val fileType = FileManager(context, lifecycleOwner).getFileType(images[position])
|
||||||
holder.bind(imageUrl,fileType)
|
|
||||||
currentViewHolder = holder
|
|
||||||
|
|
||||||
currentMediaPlayer?.let {
|
stopAndResetCurrentAudio()
|
||||||
if (it.isPlaying) it.pause()
|
|
||||||
it.seekTo(0)
|
|
||||||
}
|
|
||||||
currentMediaPlayer = null
|
|
||||||
isMediaPlayerPrepared = false
|
|
||||||
|
|
||||||
if (currentMediaPlayer?.isPlaying == true) {
|
holder.bind(imageUrl, fileType, position)
|
||||||
currentMediaPlayer?.stop()
|
|
||||||
currentMediaPlayer?.release()
|
|
||||||
}
|
|
||||||
currentMediaPlayer = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = images.size
|
override fun getItemCount(): Int = images.size
|
||||||
|
|
||||||
|
private fun stopAndResetCurrentAudio() {
|
||||||
|
currentViewHolder?.stopAndResetAudio()
|
||||||
|
currentPlayingPosition = -1
|
||||||
|
currentViewHolder = null
|
||||||
|
}
|
||||||
|
|
||||||
inner class ImageViewHolder(private val binding: ViewpagerItemsBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ImageViewHolder(private val binding: ViewpagerItemsBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
private var mediaPlayer: MediaPlayer? = null
|
|
||||||
private var seekHandler = Handler(Looper.getMainLooper())
|
private var seekHandler = Handler(Looper.getMainLooper())
|
||||||
private var seekRunnable: Runnable? = null
|
private var seekRunnable: Runnable? = null
|
||||||
|
private var mediaPlayer: MediaPlayer? = null
|
||||||
|
private var isMediaPlayerPrepared = false
|
||||||
|
private var isPlaying = false
|
||||||
|
private var currentPosition = 0
|
||||||
|
|
||||||
|
fun bind(file: File, fileType: FileManager.FileType, position: Int) {
|
||||||
|
currentPosition = position
|
||||||
|
|
||||||
|
releaseMediaPlayer()
|
||||||
|
resetAudioUI()
|
||||||
|
|
||||||
fun bind(file: File, fileType: FileManager.FileType) {
|
|
||||||
when (fileType) {
|
when (fileType) {
|
||||||
FileManager.FileType.VIDEO -> {
|
FileManager.FileType.VIDEO -> {
|
||||||
binding.imageView.visibility = View.GONE
|
binding.imageView.visibility = View.GONE
|
||||||
@@ -114,7 +113,6 @@ class ImagePreviewAdapter(
|
|||||||
binding.audioTitle.text = file.name
|
binding.audioTitle.text = file.name
|
||||||
|
|
||||||
setupAudioPlayer(file)
|
setupAudioPlayer(file)
|
||||||
setupSeekBar()
|
|
||||||
setupPlaybackControls()
|
setupPlaybackControls()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -125,27 +123,40 @@ class ImagePreviewAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun resetAudioUI() {
|
||||||
|
binding.playPause.setImageResource(R.drawable.play)
|
||||||
|
binding.audioSeekBar.value = 0f
|
||||||
|
binding.audioSeekBar.valueTo = 100f // Default value
|
||||||
|
seekRunnable?.let { seekHandler.removeCallbacks(it) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupAudioPlayer(file: File) {
|
private fun setupAudioPlayer(file: File) {
|
||||||
mediaPlayer = MediaPlayer().apply {
|
try {
|
||||||
setDataSource(file.absolutePath)
|
mediaPlayer = MediaPlayer().apply {
|
||||||
setOnPreparedListener { mp ->
|
setDataSource(file.absolutePath)
|
||||||
binding.audioSeekBar.valueTo = mp.duration.toFloat()
|
setOnPreparedListener { mp ->
|
||||||
|
binding.audioSeekBar.valueTo = mp.duration.toFloat()
|
||||||
isMediaPlayerPrepared = true
|
binding.audioSeekBar.value = 0f
|
||||||
|
setupSeekBar()
|
||||||
|
isMediaPlayerPrepared = true
|
||||||
|
}
|
||||||
|
setOnCompletionListener {
|
||||||
|
stopAndResetAudio()
|
||||||
|
}
|
||||||
|
setOnErrorListener { _, _, _ ->
|
||||||
|
releaseMediaPlayer()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
prepareAsync()
|
||||||
}
|
}
|
||||||
setOnCompletionListener {
|
} catch (e: Exception) {
|
||||||
// isPlaying = false
|
e.printStackTrace()
|
||||||
binding.playPause.setImageResource(R.drawable.play)
|
releaseMediaPlayer()
|
||||||
binding.audioSeekBar.value = 0f
|
|
||||||
|
|
||||||
seekHandler.removeCallbacks(seekRunnable!!)
|
|
||||||
}
|
|
||||||
prepareAsync()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupSeekBar() {
|
private fun setupSeekBar() {
|
||||||
binding.audioSeekBar.addOnChangeListener { slider, value, fromUser ->
|
binding.audioSeekBar.addOnChangeListener { _, value, fromUser ->
|
||||||
if (fromUser && mediaPlayer != null && isMediaPlayerPrepared) {
|
if (fromUser && mediaPlayer != null && isMediaPlayerPrepared) {
|
||||||
mediaPlayer?.seekTo(value.toInt())
|
mediaPlayer?.seekTo(value.toInt())
|
||||||
}
|
}
|
||||||
@@ -153,15 +164,18 @@ class ImagePreviewAdapter(
|
|||||||
|
|
||||||
seekRunnable = Runnable {
|
seekRunnable = Runnable {
|
||||||
mediaPlayer?.let { mp ->
|
mediaPlayer?.let { mp ->
|
||||||
if (mp.isPlaying) {
|
if (mp.isPlaying && isMediaPlayerPrepared) {
|
||||||
binding.audioSeekBar.value = mp.currentPosition.toFloat()
|
try {
|
||||||
seekHandler.postDelayed(seekRunnable!!, 100)
|
binding.audioSeekBar.value = mp.currentPosition.toFloat()
|
||||||
|
seekHandler.postDelayed(seekRunnable!!, 100)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun setupPlaybackControls() {
|
private fun setupPlaybackControls() {
|
||||||
binding.playPause.setOnClickListener {
|
binding.playPause.setOnClickListener {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
@@ -173,65 +187,127 @@ class ImagePreviewAdapter(
|
|||||||
|
|
||||||
binding.preview.setOnClickListener {
|
binding.preview.setOnClickListener {
|
||||||
mediaPlayer?.let { mp ->
|
mediaPlayer?.let { mp ->
|
||||||
val newPosition = mp.currentPosition - 10000
|
if (isMediaPlayerPrepared) {
|
||||||
mp.seekTo(maxOf(0, newPosition))
|
try {
|
||||||
binding.audioSeekBar.value = mp.currentPosition.toFloat()
|
val newPosition = mp.currentPosition - 10000
|
||||||
|
mp.seekTo(maxOf(0, newPosition))
|
||||||
|
binding.audioSeekBar.value = mp.currentPosition.toFloat()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.next.setOnClickListener {
|
binding.next.setOnClickListener {
|
||||||
mediaPlayer?.let { mp ->
|
mediaPlayer?.let { mp ->
|
||||||
val newPosition = mp.currentPosition + 10000
|
if (isMediaPlayerPrepared) {
|
||||||
mp.seekTo(minOf(mp.duration, newPosition))
|
try {
|
||||||
binding.audioSeekBar.value = mp.currentPosition.toFloat()
|
val newPosition = mp.currentPosition + 10000
|
||||||
|
mp.seekTo(minOf(mp.duration, newPosition))
|
||||||
|
binding.audioSeekBar.value = mp.currentPosition.toFloat()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playAudio() {
|
private fun playAudio() {
|
||||||
mediaPlayer?.let { mp ->
|
mediaPlayer?.let { mp ->
|
||||||
if (currentPlayingPosition != -1 && currentPlayingPosition != adapterPosition) {
|
if (isMediaPlayerPrepared) {
|
||||||
currentViewHolder?.pauseAudio()
|
try {
|
||||||
|
if (currentPlayingPosition != currentPosition) {
|
||||||
|
stopAndResetCurrentAudio()
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.start()
|
||||||
|
isPlaying = true
|
||||||
|
binding.playPause.setImageResource(R.drawable.pause)
|
||||||
|
seekRunnable?.let { seekHandler.post(it) }
|
||||||
|
|
||||||
|
currentPlayingPosition = currentPosition
|
||||||
|
currentViewHolder = this@ImageViewHolder
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
releaseMediaPlayer()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mp.start()
|
|
||||||
isPlaying = true
|
|
||||||
binding.playPause.setImageResource(R.drawable.pause)
|
|
||||||
seekHandler.post(seekRunnable!!)
|
|
||||||
currentPlayingPosition = adapterPosition
|
|
||||||
currentViewHolder = this
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pauseAudio() {
|
private fun pauseAudio() {
|
||||||
mediaPlayer?.let { mp ->
|
mediaPlayer?.let { mp ->
|
||||||
if (mp.isPlaying) {
|
try {
|
||||||
mp.pause()
|
if (mp.isPlaying) {
|
||||||
isPlaying = false
|
mp.pause()
|
||||||
binding.playPause.setImageResource(R.drawable.play)
|
isPlaying = false
|
||||||
seekHandler.removeCallbacks(seekRunnable!!)
|
binding.playPause.setImageResource(R.drawable.play)
|
||||||
|
seekRunnable?.let { seekHandler.removeCallbacks(it) }
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
releaseMediaPlayer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun stopAndResetAudio() {
|
||||||
|
try {
|
||||||
|
mediaPlayer?.let { mp ->
|
||||||
|
if (mp.isPlaying) {
|
||||||
|
mp.stop()
|
||||||
|
mp.prepare()
|
||||||
|
} else if (isMediaPlayerPrepared) {
|
||||||
|
mp.seekTo(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isPlaying = false
|
||||||
|
resetAudioUI()
|
||||||
|
|
||||||
|
if (currentPlayingPosition == currentPosition) {
|
||||||
|
currentPlayingPosition = -1
|
||||||
|
currentViewHolder = null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
releaseMediaPlayer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun releaseMediaPlayer() {
|
fun releaseMediaPlayer() {
|
||||||
mediaPlayer?.let { mp ->
|
try {
|
||||||
if (mp.isPlaying) {
|
mediaPlayer?.let { mp ->
|
||||||
mp.stop()
|
if (mp.isPlaying) {
|
||||||
|
mp.stop()
|
||||||
|
}
|
||||||
|
mp.release()
|
||||||
}
|
}
|
||||||
mp.release()
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
mediaPlayer = null
|
mediaPlayer = null
|
||||||
isPlaying = false
|
isPlaying = false
|
||||||
seekHandler.removeCallbacks(seekRunnable!!)
|
isMediaPlayerPrepared = false
|
||||||
|
seekRunnable?.let { seekHandler.removeCallbacks(it) }
|
||||||
|
|
||||||
|
if (currentPlayingPosition == currentPosition) {
|
||||||
|
currentPlayingPosition = -1
|
||||||
|
currentViewHolder = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playVideoAtPosition(position: Int) {
|
private fun playVideoAtPosition(position: Int) {
|
||||||
val nextFile = images[position]
|
if (position < images.size) {
|
||||||
val fileType = FileManager(context, lifecycleOwner).getFileType(images[position])
|
val nextFile = images[position]
|
||||||
if (fileType == FileManager.FileType.VIDEO) {
|
val fileType = FileManager(context, lifecycleOwner).getFileType(images[position])
|
||||||
val videoUri = Uri.fromFile(nextFile)
|
if (fileType == FileManager.FileType.VIDEO) {
|
||||||
binding.videoView.setVideoURI(videoUri)
|
val videoUri = Uri.fromFile(nextFile)
|
||||||
binding.videoView.start()
|
binding.videoView.setVideoURI(videoUri)
|
||||||
|
binding.videoView.start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,5 +316,14 @@ class ImagePreviewAdapter(
|
|||||||
super.onViewRecycled(holder)
|
super.onViewRecycled(holder)
|
||||||
holder.releaseMediaPlayer()
|
holder.releaseMediaPlayer()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fun onItemScrolledAway(position: Int) {
|
||||||
|
if (currentPlayingPosition == position) {
|
||||||
|
stopAndResetCurrentAudio()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun releaseAllResources() {
|
||||||
|
stopAndResetCurrentAudio()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package devs.org.calculator.adapters
|
package devs.org.calculator.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
@@ -22,9 +22,9 @@ class ListFolderAdapter(
|
|||||||
private var isSelectionMode = false
|
private var isSelectionMode = false
|
||||||
|
|
||||||
inner class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
inner class FolderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
val folderNameTextView: TextView = itemView.findViewById(R.id.folderName)
|
private val folderNameTextView: TextView = itemView.findViewById(R.id.folderName)
|
||||||
|
|
||||||
val selectedLayer: View = itemView.findViewById(R.id.selectedLayer)
|
private val selectedLayer: View = itemView.findViewById(R.id.selectedLayer)
|
||||||
|
|
||||||
fun bind(folder: File, onFolderClick: (File) -> Unit, onFolderLongClick: (File) -> Unit, isSelected: Boolean) {
|
fun bind(folder: File, onFolderClick: (File) -> Unit, onFolderLongClick: (File) -> Unit, isSelected: Boolean) {
|
||||||
folderNameTextView.text = folder.name
|
folderNameTextView.text = folder.name
|
||||||
@@ -89,6 +89,7 @@ class ListFolderAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun clearSelection() {
|
fun clearSelection() {
|
||||||
val wasInSelectionMode = isSelectionMode
|
val wasInSelectionMode = isSelectionMode
|
||||||
selectedItems.clear()
|
selectedItems.clear()
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
package devs.org.calculator.utils
|
package devs.org.calculator.utils
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Environment
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class FolderManager(private val context: Context) {
|
class FolderManager {
|
||||||
companion object {
|
|
||||||
const val HIDDEN_DIR = ".CalculatorHide"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createFolder(parentDir: File, folderName: String): Boolean {
|
fun createFolder(parentDir: File, folderName: String): Boolean {
|
||||||
val newFolder = File(parentDir, folderName)
|
val newFolder = File(parentDir, folderName)
|
||||||
return if (!newFolder.exists()) {
|
return if (!newFolder.exists()) {
|
||||||
newFolder.mkdirs()
|
newFolder.mkdirs()
|
||||||
// Create .nomedia file to hide from media scanners
|
|
||||||
File(newFolder, ".nomedia").createNewFile()
|
File(newFolder, ".nomedia").createNewFile()
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -54,20 +49,4 @@ class FolderManager(private val context: Context) {
|
|||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveFileToFolder(file: File, targetFolder: File): Boolean {
|
|
||||||
return try {
|
|
||||||
if (!targetFolder.exists()) {
|
|
||||||
targetFolder.mkdirs()
|
|
||||||
File(targetFolder, ".nomedia").createNewFile()
|
|
||||||
}
|
|
||||||
val newFile = File(targetFolder, file.name)
|
|
||||||
file.copyTo(newFile, overwrite = true)
|
|
||||||
file.delete()
|
|
||||||
true
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package devs.org.calculator.utils
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
class PrefsUtil(context: Context) {
|
class PrefsUtil(context: Context) {
|
||||||
private val prefs: SharedPreferences = context.getSharedPreferences("Calculator", Context.MODE_PRIVATE)
|
private val prefs: SharedPreferences = context.getSharedPreferences("Calculator", Context.MODE_PRIVATE)
|
||||||
@@ -13,26 +14,33 @@ class PrefsUtil(context: Context) {
|
|||||||
|
|
||||||
fun savePassword(password: String) {
|
fun savePassword(password: String) {
|
||||||
val hashedPassword = hashPassword(password)
|
val hashedPassword = hashPassword(password)
|
||||||
prefs.edit()
|
prefs.edit {
|
||||||
.putString("password", hashedPassword)
|
putString("password", hashedPassword)
|
||||||
.apply()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBoolean(key:String, value: Boolean){
|
fun setBoolean(key:String, value: Boolean){
|
||||||
return prefs.edit().putBoolean(key,value).apply()
|
return prefs.edit { putBoolean(key, value) }
|
||||||
|
|
||||||
|
}
|
||||||
|
fun setInt(key:String, value: Int){
|
||||||
|
return prefs.edit { putInt(key, value) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBoolean(key: String, defValue: Boolean = false): Boolean{
|
fun getBoolean(key: String, defValue: Boolean = false): Boolean{
|
||||||
return prefs.getBoolean(key,defValue)
|
return prefs.getBoolean(key,defValue)
|
||||||
}
|
}
|
||||||
|
fun getInt(key: String, defValue: Int): Int{
|
||||||
|
return prefs.getInt(key,defValue)
|
||||||
|
}
|
||||||
|
|
||||||
fun resetPassword(){
|
fun resetPassword(){
|
||||||
prefs.edit()
|
prefs.edit {
|
||||||
.remove("password")
|
remove("password")
|
||||||
.remove("security_question")
|
.remove("security_question")
|
||||||
.remove("security_answer")
|
.remove("security_answer")
|
||||||
.apply()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validatePassword(input: String): Boolean {
|
fun validatePassword(input: String): Boolean {
|
||||||
@@ -41,10 +49,10 @@ class PrefsUtil(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveSecurityQA(question: String, answer: String) {
|
fun saveSecurityQA(question: String, answer: String) {
|
||||||
prefs.edit()
|
prefs.edit {
|
||||||
.putString("security_question", question)
|
putString("security_question", question)
|
||||||
.putString("security_answer", hashPassword(answer))
|
.putString("security_answer", hashPassword(answer))
|
||||||
.apply()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validateSecurityAnswer(answer: String): Boolean {
|
fun validateSecurityAnswer(answer: String): Boolean {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.PermissionChecker
|
import androidx.core.content.PermissionChecker
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
class StoragePermissionUtil(private val activity: AppCompatActivity) {
|
class StoragePermissionUtil(private val activity: AppCompatActivity) {
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ class StoragePermissionUtil(private val activity: AppCompatActivity) {
|
|||||||
onGranted()
|
onGranted()
|
||||||
} else {
|
} else {
|
||||||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
|
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
|
||||||
data = Uri.parse("package:${activity.packageName}")
|
data = "package:${activity.packageName}".toUri()
|
||||||
}
|
}
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="800dp"
|
android:width="50dp"
|
||||||
android:height="800dp"
|
android:height="50dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<corners android:bottomLeftRadius="15dp" android:bottomRightRadius="15dp"/>
|
<corners android:bottomLeftRadius="15dp" android:bottomRightRadius="15dp"/>
|
||||||
<solid android:color="?attr/cardForegroundColor"/>
|
<solid android:color="?attr/colorSecondaryContainer"/>
|
||||||
</shape>
|
</shape>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="50dp"
|
||||||
android:height="24dp"
|
android:height="50dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@color/textColor"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8l-6,-6H6zM13,9V3.5L18.5,9H13z"/>
|
android:pathData="M13.172,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V8.828c0,-0.53 -0.211,-1.039 -0.586,-1.414l-4.828,-4.828C14.211,2.211 13.702,2 13.172,2zM15,18H9c-0.552,0 -1,-0.448 -1,-1v0c0,-0.552 0.448,-1 1,-1h6c0.552,0 1,0.448 1,1v0C16,17.552 15.552,18 15,18zM15,14H9c-0.552,0 -1,-0.448 -1,-1v0c0,-0.552 0.448,-1 1,-1h6c0.552,0 1,0.448 1,1v0C16,13.552 15.552,14 15,14zM13,9V3.5L18.5,9H13z"/>
|
||||||
</vector>
|
</vector>
|
||||||
@@ -39,57 +39,38 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:id="@+id/folderName"/>
|
android:id="@+id/folderName"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_edit"
|
app:icon="@drawable/ic_edit"
|
||||||
app:tint="?attr/colorPrimary"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:padding="9dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:background="#00000000"
|
|
||||||
android:id="@+id/edit"/>
|
android:id="@+id/edit"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/delete"
|
android:id="@+id/delete"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="#00000000"
|
app:icon="@drawable/ic_delete"
|
||||||
android:padding="9dp"
|
style="@style/Widget.Material3.Button.IconButton" />
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:src="@drawable/ic_delete"
|
|
||||||
app:tint="?attr/colorPrimary"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/menuButton"
|
android:id="@+id/menuButton"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_more"
|
app:icon="@drawable/ic_more"
|
||||||
app:tint="?attr/colorPrimary"
|
style="@style/Widget.Material3.Button.IconButton"/>
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:padding="9dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:background="#00000000"/>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_list"
|
app:icon="@drawable/ic_list"
|
||||||
android:scaleType="fitCenter"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
app:tint="?attr/colorPrimary"
|
|
||||||
android:background="#00000000"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:id="@+id/folderOrientation"/>
|
android:id="@+id/folderOrientation"/>
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_settings"
|
app:icon="@drawable/ic_settings"
|
||||||
android:scaleType="fitCenter"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
app:tint="?attr/colorPrimary"
|
|
||||||
|
|
||||||
android:background="#00000000"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:id="@+id/settings"/>
|
android:id="@+id/settings"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -128,7 +109,7 @@
|
|||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="10dp"
|
android:padding="10dp"
|
||||||
android:text="@string/no_items_available_add_one_by_clicking_on_the_plus_button"
|
android:text="@string/there_is_no_folders_available_create_one_by_clicking_on_the_add_folder_button_showing_in_the_bottom"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
android:layout_margin="0dp"
|
android:layout_margin="0dp"
|
||||||
android:background="@drawable/bottom_corner"
|
android:background="@drawable/bottom_corner"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHeight_percent="0.3"
|
app:layout_constraintHeight_percent="0.4"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
|
android:paddingTop="27dp"
|
||||||
android:gravity="end|bottom"
|
android:gravity="end|bottom"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/total"
|
app:layout_constraintBottom_toTopOf="@+id/total"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:autoSizeMaxTextSize="40sp"
|
android:autoSizeMaxTextSize="40sp"
|
||||||
android:autoSizeMinTextSize="24sp"
|
android:autoSizeMinTextSize="12sp"
|
||||||
android:autoSizeStepGranularity="2sp"
|
android:autoSizeStepGranularity="2sp"
|
||||||
android:autoSizeTextType="uniform"
|
android:autoSizeTextType="uniform"
|
||||||
android:gravity="end|bottom"
|
android:gravity="end|bottom"
|
||||||
@@ -85,7 +86,7 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/displayContainer">
|
app:layout_constraintTop_toBottomOf="@id/displayContainer">
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
@@ -95,49 +96,68 @@
|
|||||||
android:id="@+id/btnClear"
|
android:id="@+id/btnClear"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:layout_weight="1"
|
android:backgroundTint="?attr/colorSecondaryContainer"
|
||||||
android:text="C"
|
android:text="C"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnPercent"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="spread"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnPercent"
|
android:id="@+id/btnPercent"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:backgroundTint="?attr/colorSecondaryContainer"
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="%"
|
android:text="%"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
android:layout_marginHorizontal="3dp"
|
||||||
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnDivide"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btnClear"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnDivide"
|
android:id="@+id/btnDivide"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:backgroundTint="?attr/colorSecondaryContainer"
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="÷"
|
android:text="÷"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
android:layout_marginHorizontal="3dp"
|
||||||
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/cut"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btnPercent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/cut"
|
android:id="@+id/cut"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_marginHorizontal="4dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginVertical="8dp"
|
|
||||||
android:background="@drawable/gradient_bg"
|
android:background="@drawable/gradient_bg"
|
||||||
|
android:scaleType="centerInside"
|
||||||
android:src="@drawable/backspace"
|
android:src="@drawable/backspace"
|
||||||
android:scaleType="centerInside"/>
|
android:layout_marginHorizontal="3dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btnDivide"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
@@ -147,10 +167,16 @@
|
|||||||
android:id="@+id/btn7"
|
android:id="@+id/btn7"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="7"
|
android:text="7"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn8"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="spread"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp" />
|
||||||
|
|
||||||
@@ -158,21 +184,32 @@
|
|||||||
android:id="@+id/btn8"
|
android:id="@+id/btn8"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="8"
|
android:text="8"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn9"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn7"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn9"
|
android:id="@+id/btn9"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="9"
|
android:text="9"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnMultiply"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn8"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp" />
|
||||||
|
|
||||||
@@ -180,18 +217,22 @@
|
|||||||
android:id="@+id/btnMultiply"
|
android:id="@+id/btnMultiply"
|
||||||
style="@style/CustomMaterialButton"
|
style="@style/CustomMaterialButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_marginHorizontal="4dp"
|
|
||||||
android:layout_marginVertical="8dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:textColor="@color/white"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="×"
|
android:text="×"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn9"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
@@ -201,51 +242,71 @@
|
|||||||
android:id="@+id/btn4"
|
android:id="@+id/btn4"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="4"
|
android:text="4"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn5"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="spread"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn5"
|
android:id="@+id/btn5"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="5"
|
android:text="5"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn6"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn4"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn6"
|
android:id="@+id/btn6"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="6"
|
android:text="6"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnMinus"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn5"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnMinus"
|
android:id="@+id/btnMinus"
|
||||||
style="@style/CustomMaterialButton"
|
style="@style/CustomMaterialButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_marginHorizontal="4dp"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:layout_marginVertical="8dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:text="-"
|
android:text="-"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn6"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
@@ -255,92 +316,144 @@
|
|||||||
android:id="@+id/btn1"
|
android:id="@+id/btn1"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="1"
|
android:text="1"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn2"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="spread"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn2"
|
android:id="@+id/btn2"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="2"
|
android:text="2"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn3"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn1"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn3"
|
android:id="@+id/btn3"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="3"
|
android:text="3"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnPlus"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn2"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnPlus"
|
android:id="@+id/btnPlus"
|
||||||
style="@style/CustomMaterialButton"
|
style="@style/CustomMaterialButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_marginHorizontal="4dp"
|
|
||||||
android:layout_marginVertical="8dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="+"
|
android:text="+"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn3"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn00"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginHorizontal="3dp"
|
||||||
|
android:text="00"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textSize="30sp"
|
||||||
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btn0"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="spread"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn0"
|
android:id="@+id/btn0"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:layout_weight="1"
|
||||||
android:layout_weight="2"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="0"
|
android:text="0"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnDot"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn00"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnDot"
|
android:id="@+id/btnDot"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="4dp"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="."
|
android:text="."
|
||||||
|
android:layout_weight="1"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1.15"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnEquals"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btn0"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnEquals"
|
android:id="@+id/btnEquals"
|
||||||
style="@style/CustomMaterialButton"
|
style="@style/CustomMaterialButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_marginHorizontal="4dp"
|
|
||||||
android:layout_marginVertical="8dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:textColor="@color/white"
|
android:layout_marginHorizontal="3dp"
|
||||||
android:text="="
|
android:text="="
|
||||||
|
android:textColor="@color/white"
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
app:cornerRadius="15dp" />
|
app:cornerRadius="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/btnDot"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,9 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:cardCornerRadius="10dp"
|
app:cardCornerRadius="10dp"
|
||||||
app:cardElevation="5dp">
|
android:background="#00000000"
|
||||||
|
android:backgroundTint="#00000000"
|
||||||
|
app:cardElevation="0dp">
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/appLogo"
|
android:id="@+id/appLogo"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
|
|||||||
@@ -40,16 +40,12 @@
|
|||||||
android:id="@+id/folderName"/>
|
android:id="@+id/folderName"/>
|
||||||
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/menuButton"
|
android:id="@+id/menuButton"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_more"
|
app:icon="@drawable/ic_more"
|
||||||
app:tint="?attr/colorPrimary"
|
style="@style/Widget.Material3.Button.IconButton"/>
|
||||||
android:scaleType="fitCenter"
|
|
||||||
android:padding="7dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:background="#00000000"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -79,7 +75,7 @@
|
|||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:src="@drawable/ic_no_items" />
|
android:src="@drawable/ic_file" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/noItemsTxt"
|
android:id="@+id/noItemsTxt"
|
||||||
|
|||||||
@@ -10,8 +10,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="4dp"
|
android:layout_margin="4dp"
|
||||||
app:cardCornerRadius="8dp"
|
app:cardCornerRadius="8dp">
|
||||||
app:cardElevation="2dp">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -1,24 +1,33 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="12dp"
|
android:layout_margin="3dp"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:id="@+id/folderIcon"
|
|
||||||
android:layout_width="34dp"
|
|
||||||
android:layout_height="34dp"
|
|
||||||
android:src="@drawable/ic_folder"
|
|
||||||
app:tint="?attr/colorPrimary" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/folderName"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:padding="12dp"
|
||||||
android:textSize="18sp"/>
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/folderIcon"
|
||||||
|
android:layout_width="34dp"
|
||||||
|
android:layout_height="34dp"
|
||||||
|
android:src="@drawable/ic_folder"
|
||||||
|
app:tint="?attr/colorPrimary" />
|
||||||
|
|
||||||
</LinearLayout>
|
<TextView
|
||||||
|
android:id="@+id/folderName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:textSize="18sp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
@@ -15,13 +15,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/cardView"
|
android:id="@+id/cardView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:cardCornerRadius="10dp"
|
app:cardCornerRadius="10dp"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
app:cardElevation="3dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintDimensionRatio="1:1"
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@@ -49,7 +48,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|||||||
@@ -42,7 +42,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
app:cardCornerRadius="15dp"
|
app:cardCornerRadius="15dp"
|
||||||
app:cardElevation="10dp"
|
|
||||||
android:layout_margin="20dp">
|
android:layout_margin="20dp">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
<item name="android:windowLightStatusBar">false</item>
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
|
<item name="colorSecondaryContainer">#481A4324</item>
|
||||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
|
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<string name="unknown_file">Unknown File</string>
|
<string name="unknown_file">Unknown File</string>
|
||||||
<string name="details"> DETAILS</string>
|
<string name="details"> DETAILS</string>
|
||||||
<string name="audio_hidded_successfully">Audios hidden successfully</string>
|
<string name="audio_hidded_successfully">Audios hidden successfully</string>
|
||||||
<string name="no_items_available_add_one_by_clicking_on_the_plus_button">No Items Available, Add one by clicking on the</string>
|
<string name="no_items_available_add_one_by_clicking_on_the_plus_button">No Files Available, Add one by clicking on the \'+\' button</string>
|
||||||
<string name="now_enter_button">Now Enter \'=\' button</string>
|
<string name="now_enter_button">Now Enter \'=\' button</string>
|
||||||
<string name="enter_123456">Enter 123456</string>
|
<string name="enter_123456">Enter 123456</string>
|
||||||
<string name="create_folder">Create Folder</string>
|
<string name="create_folder">Create Folder</string>
|
||||||
@@ -126,4 +126,26 @@
|
|||||||
<string name="security_question_for_password_reset">Security Question (For Password Reset)</string>
|
<string name="security_question_for_password_reset">Security Question (For Password Reset)</string>
|
||||||
<string name="security_answer">Security Answer</string>
|
<string name="security_answer">Security Answer</string>
|
||||||
<string name="save_password">Save Password</string>
|
<string name="save_password">Save Password</string>
|
||||||
|
<string name="there_is_no_folders_available_create_one_by_clicking_on_the_add_folder_button_showing_in_the_bottom">There is no Folders Available, create one by clicking on the \'Add Folder\' Button showing in the bottom.</string>
|
||||||
|
<string name="storage_permission">Storage Permission</string>
|
||||||
|
<string name="to_ensure_the_app_works_properly_and_allows_you_to_easily_hide_or_un_hide_your_private_files_please_grant_storage_access_permission">To ensure the app works properly and allows you to easily hide or un-hide your private files, please grant storage access permission.\n</string>
|
||||||
|
<string name="for_devices_running_android_11_or_higher_you_ll_need_to_grant_the_all_files_access_permission">For devices running Android 11 or higher, you\'ll need to grant the \'All Files Access\' permission.</string>
|
||||||
|
<string name="grant_permission">Grant Permission</string>
|
||||||
|
<string name="later">Later</string>
|
||||||
|
<string name="storage_permission_is_required_for_the_app_to_function_properly">Storage permission is required for the app to function properly</string>
|
||||||
|
<string name="you_can_grant_permission_later_from_settings">You can grant permission later from Settings</string>
|
||||||
|
<string name="permission_granted">Permission granted</string>
|
||||||
|
<string name="permission_denied">Permission denied</string>
|
||||||
|
<string name="github_profile">https://github.com/binondi</string>
|
||||||
|
<string name="calculator_hide_files">%1$s/calculator-hide-files</string>
|
||||||
|
<string name="would_you_like_to_set_a_specific_theme_mode">Would you like to set a specific theme mode?</string>
|
||||||
|
<string name="no">No</string>
|
||||||
|
<string name="could_not_open_url">Could not open URL</string>
|
||||||
|
<string name="files_copied_successfully">Files copied successfully</string>
|
||||||
|
<string name="some_files_could_not_be_copied">Some files could not be copied</string>
|
||||||
|
<string name="files_moved_successfully">Files moved successfully</string>
|
||||||
|
<string name="some_files_could_not_be_moved">Some files could not be moved</string>
|
||||||
|
<string name="ok">OK</string>
|
||||||
|
<string name="if_you_turn_on_off_this_option_dynamic_theme_changes_will_be_visible_after_you_reopen_the_app">If you turn on/off this option, dynamic theme changes will be visible after you reopen the app.</string>
|
||||||
|
<string name="attention">Attention!</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
<item name="colorControlNormal">#483CFF61</item>
|
<item name="colorControlNormal">#483CFF61</item>
|
||||||
|
<item name="colorSecondaryContainer">#48BDFFCB</item>
|
||||||
|
|
||||||
<item name="android:windowLightStatusBar">true</item>
|
<item name="android:windowLightStatusBar">true</item>
|
||||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item>
|
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user