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