14 Commits

Author SHA1 Message Date
Owen
92dcfbd0ae sorting + slideshow 2025-08-21 10:41:41 -04:00
Owen
db2326f3e7 dedicated restore directory 2025-07-23 11:29:43 -04:00
Owen
5efeb6876b sort folders alphabetically and run image slideshows 2025-07-23 11:29:43 -04:00
Binondi Borthakur
82982aa221 Added Android Freeware 2025-07-12 10:44:51 +05:30
Binondi Borthakur
6f151554f0 Updated Version 2025-07-12 10:34:45 +05:30
Binondi
5ecd3ec7d1 Merge remote-tracking branch 'origin/master' 2025-07-11 14:00:13 +05:30
Binondi
946953d4eb Fixed - App Crashing in lower android versions, added edge to edge for devices higher then android 15 2025-07-11 13:59:47 +05:30
Binondi Borthakur
18172f5191 Update README.md 2025-06-09 00:41:38 +05:30
Binondi Borthakur
603d96b672 Added - payment qr 2025-06-09 00:35:57 +05:30
Binondi Borthakur
78ea4596ea Update README.md 2025-06-09 00:34:48 +05:30
Binondi Borthakur
a70a569b57 Added - Payment QR 2025-06-09 00:31:00 +05:30
Binondi Borthakur
df0db1a479 Made Some. Changes 2025-06-09 00:30:18 +05:30
Binondi Borthakur
9cdc6eb1a4 Added - Payment QR 2025-06-09 00:21:45 +05:30
Binondi Borthakur
913af83b90 Updated Some Details 2025-06-09 00:11:45 +05:30
28 changed files with 470 additions and 165 deletions

View File

@@ -5,11 +5,11 @@
# 📂 Calculator Hide File App for Android 📂
<a href="https://github.com/Binondi/Calculator-Hide-Files/releases/latest">
<img alt="Latest release" src="https://img.shields.io/badge/Releases-v1.4.0-blue?logo=github&style=for-the-badge">
<img alt="Latest release" src="https://img.shields.io/badge/Releases-v1.4.2-blue?logo=github&style=for-the-badge">
</a>
<a href="https://github.com/Binondi/Calculator-Hide-Files/releases/latest">
<img alt="Downloads" src="https://img.shields.io/github/downloads/Binondi/Calculator-Hide-Files/total?style=for-the-badge">
<img alt="Downloads" src="https://img.shields.io/badge/downloads-1.1k-blue?logo=github&style=for-the-badge">
</a>
<a href="LICENSE">
@@ -23,7 +23,7 @@
<h4>Download</h4>
<a>[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png" alt="Get it on GitHub" height="80">](https://github.com/binondi/Calculator-Hide-Files/releases) </a><a href="https://apt.izzysoft.de/fdroid/index/apk/devs.org.calculator"><img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="80"></a>
<a>[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png" alt="Get it on GitHub" height="80">](https://github.com/binondi/Calculator-Hide-Files/releases) </a><a href="https://apt.izzysoft.de/fdroid/index/apk/devs.org.calculator"><img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="80"></a> <a href="https://www.androidfreeware.net/download-apk-devs-org-calculator.html"><img src="https://www.androidfreeware.net/images/androidfreeware-badge.png" height="80"></a>
</div>
@@ -134,6 +134,11 @@ If you find this app useful, please consider supporting the development. 🙏
[![Sponsor on GitHub](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/Binondi)
[![Donate via PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://paypal.me/BinondiBorthakur56)
[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://buymeacoffee.com/binondi)
- **UPI ID** 📱
``
binondi@naviaxis
``
---
## 🔧 Contributing

View File

@@ -13,8 +13,8 @@ android {
minSdk = 26
//noinspection OldTargetApi
targetSdk = 34
versionCode = 6
versionName = "1.4.1"
versionCode = 7
versionName = "1.4.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -70,6 +70,7 @@ dependencies {
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.gridlayout)
implementation(libs.androidx.lifecycle.process)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

View File

@@ -11,8 +11,8 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 4,
"versionName": "1.3",
"versionCode": 6,
"versionName": "1.4.1",
"outputFile": "app-release.apk"
}
],

View File

@@ -11,7 +11,10 @@ import android.view.WindowManager
import android.widget.EditText
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import devs.org.calculator.R
@@ -47,7 +50,12 @@ class HiddenActivity : AppCompatActivity() {
fileManager = FileManager(this, this)
folderManager = FolderManager()
dialogUtil = DialogUtil(this)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
setupInitialUIState()
setupClickListeners()
@@ -110,6 +118,13 @@ class HiddenActivity : AppCompatActivity() {
binding.folderOrientation.setIconResource(R.drawable.ic_list)
}
}
binding.random.setOnClickListener {
val folders = folderManager.getFoldersInDirectory(hiddenDir)
val randomIndex = (Math.random() * folders.size).toInt()
val folder = folders[randomIndex]
startActivity(Intent(this,ViewFolderActivity::class.java).putExtra("folder",folder.toString()))
}
}
private fun showGridUI() {
@@ -391,6 +406,7 @@ class HiddenActivity : AppCompatActivity() {
}
private fun showFolderViewIcons() {
binding.random.visibility = View.VISIBLE
binding.folderOrientation.visibility = View.VISIBLE
binding.settings.visibility = View.VISIBLE
binding.delete.visibility = View.GONE
@@ -404,6 +420,7 @@ class HiddenActivity : AppCompatActivity() {
}
}
private fun showFolderSelectionIcons() {
binding.random.visibility = View.GONE
binding.folderOrientation.visibility = View.GONE
binding.settings.visibility = View.GONE
binding.delete.visibility = View.VISIBLE

View File

@@ -24,6 +24,10 @@ import devs.org.calculator.utils.PrefsUtil
import net.objecthunter.exp4j.ExpressionBuilder
import java.util.regex.Pattern
import androidx.core.content.edit
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import devs.org.calculator.utils.StoragePermissionUtil
class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.DialogCallback {
private lateinit var binding: ActivityMainBinding
@@ -36,6 +40,8 @@ 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 lateinit var storagePermissionUtil: StoragePermissionUtil
private lateinit var permissionLauncher: ActivityResultLauncher<Array<String>>
@RequiresApi(Build.VERSION_CODES.R)
override fun onCreate(savedInstanceState: Bundle?) {
@@ -43,15 +49,30 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, 0, systemBars.right, systemBars.bottom)
insets
}
permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
storagePermissionUtil.handlePermissionResult(permissions)
}
// Initialize StoragePermissionUtil
storagePermissionUtil = StoragePermissionUtil(this)
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
handleActivityResult(result)
}
if (sp.getBoolean("isFirst", true)){
binding.display.text = getString(R.string.enter_123456)
}
if(!Environment.isExternalStorageManager()) {
if (!storagePermissionUtil.hasStoragePermission()) {
dialogUtil.showMaterialDialog(
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) +
@@ -61,7 +82,10 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
getString(R.string.later),
object : DialogUtil.DialogCallback {
override fun onPositiveButtonClicked() {
fileManager.askPermission(this@MainActivity)
storagePermissionUtil.requestStoragePermission(permissionLauncher) {
Toast.makeText(this@MainActivity, getString(R.string.permission_granted), Toast.LENGTH_SHORT).show()
}
}
override fun onNegativeButtonClicked() {
@@ -75,9 +99,11 @@ class MainActivity : AppCompatActivity(), DialogActionsCallback, DialogUtil.Dial
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")

View File

@@ -4,9 +4,13 @@ import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2
import devs.org.calculator.R
@@ -18,6 +22,7 @@ import devs.org.calculator.utils.DialogUtil
import devs.org.calculator.utils.FileManager
import devs.org.calculator.utils.PrefsUtil
import devs.org.calculator.utils.SecurityUtils
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.launch
import java.io.File
@@ -37,12 +42,33 @@ class PreviewActivity : AppCompatActivity() {
private val hiddenFileRepository: HiddenFileRepository by lazy {
HiddenFileRepository(AppDatabase.getDatabase(this).hiddenFileDao())
}
private var slideshowRunning = false
private val slideshowDelay = 2000L
private val slideshowRunner = object : Runnable {
override fun run() {
if (slideshowRunning) {
if (currentPosition + 1 >= files.size) {
currentPosition = 0
} else {
currentPosition += 1
}
binding.viewPager.setCurrentItem(currentPosition, true)
mainHandler.postDelayed(this, slideshowDelay)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPreviewBinding.inflate(layoutInflater)
setContentView(binding.root)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
fileManager = FileManager(this, this)
currentPosition = intent.getIntExtra("position", 0)
@@ -126,6 +152,11 @@ class PreviewActivity : AppCompatActivity() {
adapter = ImagePreviewAdapter(this, this)
adapter.images = files
adapter.onSlideshowShouldStop = {
if (slideshowRunning) {
stopSlideshow()
}
}
binding.viewPager.adapter = adapter
if (currentPosition < files.size) {
binding.viewPager.setCurrentItem(currentPosition, false)
@@ -171,6 +202,34 @@ class PreviewActivity : AppCompatActivity() {
currentPosition = position
}
})
if (filetype != FileManager.FileType.IMAGE) {
binding.startSlideshow.visibility = View.GONE
}
binding.startSlideshow.setOnClickListener {
startSlideshow()
}
}
private fun startSlideshow() {
if (!slideshowRunning) {
slideshowRunning = true
toggleToolbars()
mainHandler.postDelayed(slideshowRunner, slideshowDelay)
adapter.setImageZoomable(false)
}
}
private fun stopSlideshow() {
slideshowRunning = false
toggleToolbars()
mainHandler.removeCallbacks(slideshowRunner)
adapter.setImageZoomable(true)
}
private fun toggleToolbars() {
val visibility = if (slideshowRunning) View.GONE else View.VISIBLE
binding.toolbar.visibility = visibility
binding.footer.visibility = visibility
}
private fun handleDeleteFile() {

View File

@@ -0,0 +1,43 @@
package devs.org.calculator.activities
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
abstract class SecureBaseActivity : AppCompatActivity() {
class AppLifecycleObserver : DefaultLifecycleObserver {
companion object {
var wasInBackground = false
}
override fun onStart(owner: LifecycleOwner) {
wasInBackground = true
}
override fun onStop(owner: LifecycleOwner) {
wasInBackground = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
}
override fun onResume() {
super.onResume()
if (AppLifecycleObserver.wasInBackground) {
AppLifecycleObserver.wasInBackground = false
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
finish()
}
}
}

View File

@@ -6,9 +6,12 @@ import android.view.View
import android.view.WindowManager
import android.widget.EditText
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.color.DynamicColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
@@ -29,6 +32,12 @@ class SettingsActivity : AppCompatActivity() {
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
prefs = PrefsUtil(this)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
DEV_GITHUB_URL = getString(R.string.github_profile)
GITHUB_URL = getString(R.string.calculator_hide_files, DEV_GITHUB_URL)
setupUI()

View File

@@ -5,7 +5,10 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.color.DynamicColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputEditText
@@ -26,7 +29,12 @@ class SetupPasswordActivity : AppCompatActivity() {
binding = ActivitySetupPasswordBinding.inflate(layoutInflater)
binding2 = ActivityChangePasswordBinding.inflate(layoutInflater)
setContentView(binding.root)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
prefsUtil = PrefsUtil(this)
hasPassword = prefsUtil.hasPassword()

View File

@@ -40,6 +40,9 @@ import android.widget.CheckBox
import android.widget.CompoundButton
import android.app.AlertDialog
import android.view.WindowManager
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import devs.org.calculator.adapters.FileAdapter
class ViewFolderActivity : AppCompatActivity() {
@@ -71,6 +74,12 @@ class ViewFolderActivity : AppCompatActivity() {
binding = ActivityViewFolderBinding.inflate(layoutInflater)
setContentView(binding.root)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
setupAnimations()
initialize()
setupClickListeners()
@@ -318,6 +327,10 @@ class ViewFolderActivity : AppCompatActivity() {
binding.swipeLayout.visibility = View.VISIBLE
binding.noItems.visibility = View.GONE
binding.selectAllButton.setOnClickListener {
fileAdapter?.toggleSelectAll()
}
binding.menuButton.setOnClickListener {
fileAdapter?.let { adapter ->
showFileOptionsMenu(adapter.getSelectedItems())
@@ -753,6 +766,7 @@ class ViewFolderActivity : AppCompatActivity() {
private fun showFileViewIcons() {
binding.menuButton.visibility = View.GONE
binding.selectAllButton.visibility = View.GONE
binding.fabExpend.visibility = View.VISIBLE
binding.addImage.visibility = View.INVISIBLE
binding.addVideo.visibility = View.INVISIBLE
@@ -764,6 +778,7 @@ class ViewFolderActivity : AppCompatActivity() {
private fun showFileSelectionIcons() {
binding.menuButton.visibility = View.VISIBLE
binding.selectAllButton.visibility = View.VISIBLE
binding.fabExpend.visibility = View.GONE
binding.addImage.visibility = View.INVISIBLE
binding.addVideo.visibility = View.INVISIBLE

View File

@@ -495,6 +495,31 @@ class FileAdapter(
}
}
fun toggleSelectAll() {
if (!isSelectionMode) {
isSelectionMode = true
notifySelectionModeChange()
}
val filesInFolder = FolderManager().getFilesInFolder(currentFolder)
if (selectedItems.size == filesInFolder.size) {
selectedItems.clear()
onSelectionCountChanged(0)
notifyDataSetChanged()
// for (i in 0 until filesInFolder.size) {
// notifyItemChanged(i)
// notifyChan
// }
} else {
for (i in 0 until filesInFolder.size) {
if (!selectedItems.contains(i)) {
selectedItems.add(i)
notifyItemChanged(i)
}
}
onSelectionCountChanged(filesInFolder.size)
}
}
@SuppressLint("NotifyDataSetChanged")
fun exitSelectionMode() {
if (isSelectionMode) {

View File

@@ -36,11 +36,14 @@ class ImagePreviewAdapter(
private val hiddenFileRepository: HiddenFileRepository by lazy {
HiddenFileRepository(AppDatabase.getDatabase(context).hiddenFileDao())
}
private var canZoomOnImages: Boolean = true
var images: List<File>
get() = differ.currentList
set(value) = differ.submitList(value)
var onSlideshowShouldStop: () -> Unit = {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val binding = ViewpagerItemsBinding.inflate(LayoutInflater.from(context), parent, false)
return ImageViewHolder(binding)
@@ -56,6 +59,11 @@ class ImagePreviewAdapter(
override fun getItemCount(): Int = images.size
fun setImageZoomable(zoomable: Boolean) {
currentViewHolder?.setImageViewCanZoom(zoomable)
canZoomOnImages = zoomable
}
private fun stopAndResetCurrentAudio() {
currentViewHolder?.stopAndResetAudio()
currentPlayingPosition = -1
@@ -153,6 +161,11 @@ class ImagePreviewAdapter(
binding.imageView.visibility = View.VISIBLE
binding.videoView.visibility = View.GONE
binding.audioBg.visibility = View.GONE
binding.imageView.isZoomable = canZoomOnImages
binding.imageView.doubleTapToZoom = canZoomOnImages
binding.imageView.setOnClickListener {
onSlideshowShouldStop()
}
Glide.with(context)
.load(uri)
.error(R.drawable.encrypted)
@@ -181,6 +194,11 @@ class ImagePreviewAdapter(
binding.imageView.visibility = View.VISIBLE
binding.audioBg.visibility = View.GONE
binding.videoView.visibility = View.GONE
binding.imageView.isZoomable = canZoomOnImages
binding.imageView.doubleTapToZoom = canZoomOnImages
binding.imageView.setOnClickListener {
onSlideshowShouldStop()
}
Glide.with(context)
.load(uri)
.error(R.drawable.encrypted)
@@ -193,6 +211,11 @@ class ImagePreviewAdapter(
}
}
fun setImageViewCanZoom(zoomEnabled: Boolean) {
binding.imageView.doubleTapToZoom = zoomEnabled
binding.imageView.isZoomable = zoomEnabled
}
fun getFileFromUri(context: Context, uri: Uri): File? {
return try {
val inputStream = context.contentResolver.openInputStream(uri)

View File

@@ -123,7 +123,7 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
val contentResolver = context.contentResolver
// Get the target directory
val targetDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val targetDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES + "/Restore")
targetDir.mkdirs()
// Create target file

View File

@@ -39,7 +39,7 @@ class FolderManager {
directory.listFiles()?.filter { it.isDirectory && it.name != ".nomedia" } ?: emptyList()
} else {
emptyList()
}
}.sortedBy { it.name.lowercase() }
}
fun getFilesInFolder(folder: File): List<File> {

View File

@@ -7,6 +7,7 @@ import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
@@ -15,20 +16,15 @@ import androidx.core.content.PermissionChecker
import androidx.core.net.toUri
class StoragePermissionUtil(private val activity: AppCompatActivity) {
private val requestPermissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
if (permissions.all { it.value }) {
onPermissionGranted?.invoke()
}
}
private var onPermissionGranted: (() -> Unit)? = null
fun requestStoragePermission(onGranted: () -> Unit) {
fun requestStoragePermission(
launcher: ActivityResultLauncher<Array<String>>,
onGranted: () -> Unit
) {
onPermissionGranted = onGranted
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
if (Environment.isExternalStorageManager()) {
@@ -45,7 +41,7 @@ class StoragePermissionUtil(private val activity: AppCompatActivity) {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
requestPermissionLauncher.launch(permissions)
launcher.launch(permissions)
}
}
}
@@ -66,4 +62,10 @@ class StoragePermissionUtil(private val activity: AppCompatActivity) {
writePermission == PermissionChecker.PERMISSION_GRANTED
}
}
}
fun handlePermissionResult(permissions: Map<String, Boolean>) {
if (permissions.all { it.value }) {
onPermissionGranted?.invoke()
}
}
}

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M340,680Q365,680 382.5,662.5Q400,645 400,620Q400,595 382.5,577.5Q365,560 340,560Q315,560 297.5,577.5Q280,595 280,620Q280,645 297.5,662.5Q315,680 340,680ZM340,400Q365,400 382.5,382.5Q400,365 400,340Q400,315 382.5,297.5Q365,280 340,280Q315,280 297.5,297.5Q280,315 280,340Q280,365 297.5,382.5Q315,400 340,400ZM620,680Q645,680 662.5,662.5Q680,645 680,620Q680,595 662.5,577.5Q645,560 620,560Q595,560 577.5,577.5Q560,595 560,620Q560,645 577.5,662.5Q595,680 620,680ZM620,400Q645,400 662.5,382.5Q680,365 680,340Q680,315 662.5,297.5Q645,280 620,280Q595,280 577.5,297.5Q560,315 560,340Q560,365 577.5,382.5Q595,400 620,400ZM200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760ZM200,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L200,760Q200,760 200,760Q200,760 200,760L200,200Q200,200 200,200Q200,200 200,200Z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M268,720L42,494L99,438L269,608L269,608L325,664L268,720ZM494,720L268,494L324,437L494,607L862,239L918,296L494,720ZM494,494L437,438L635,240L692,296L494,494Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<path
android:fillColor="@color/svgTintColor"
android:pathData="M10,8v8l5,-4 -5,-4zM19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,5h14v14z"/>
</vector>

View File

@@ -5,74 +5,86 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".activities.SetupPasswordActivity">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/change_password"
android:textSize="24sp"
android:textStyle="bold"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilOldPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:hint="@string/enter_old_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tvTitle">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/change_password"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etOldPassword"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilOldPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:singleLine="true"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
android:layout_marginTop="32dp"
android:hint="@string/enter_old_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tvTitle">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilNewPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/enter_new_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tilOldPassword">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etOldPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:inputType="number"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etNewPassword"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilNewPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:singleLine="true"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
android:layout_marginTop="16dp"
android:hint="@string/enter_new_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tilOldPassword">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnChangePassword"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="32dp"
android:padding="12dp"
android:text="@string/change_password"
app:layout_constraintTop_toBottomOf="@id/tilNewPassword" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etNewPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:inputType="number"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnResetPassword"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/forgot_password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnChangePassword" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnChangePassword"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="32dp"
android:padding="12dp"
android:text="@string/change_password"
app:layout_constraintTop_toBottomOf="@id/tilNewPassword" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnResetPassword"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/forgot_password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnChangePassword" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -60,6 +60,12 @@
app:icon="@drawable/ic_more"
style="@style/Widget.Material3.Button.IconButton"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_dice"
style="@style/Widget.Material3.Button.IconButton"
android:id="@+id/random" />
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@@ -2,6 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="@+id/main"
android:layout_height="match_parent"
android:orientation="vertical">
@@ -13,6 +14,7 @@
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingLeft="15dp"
android:paddingRight="15dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<androidx.appcompat.widget.AppCompatImageButton
@@ -25,11 +27,20 @@
android:id="@+id/back"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:textSize="22sp"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/preview_file"/>
android:text="@string/preview_file"
android:layout_weight="1"/>
<androidx.appcompat.widget.AppCompatImageButton
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_slideshow"
android:scaleType="fitCenter"
android:background="#00000000"
android:padding="8dp"
android:id="@+id/start_slideshow"/>
</LinearLayout>
<androidx.viewpager2.widget.ViewPager2
@@ -43,6 +54,7 @@
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"

View File

@@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/main"
android:layout_height="match_parent"
tools:context=".activities.SettingsActivity">

View File

@@ -5,104 +5,116 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".activities.SetupPasswordActivity">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/setup_password"
android:textSize="24sp"
android:textStyle="bold"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:padding="18dp"
android:gravity="center_horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:hint="@string/enter_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tvTitle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/setup_password"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:singleLine="true"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
android:layout_marginTop="32dp"
android:hint="@string/enter_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tvTitle">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilConfirmPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/confirm_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tilPassword">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:inputType="number"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etConfirmPassword"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilConfirmPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:singleLine="true"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
android:layout_marginTop="16dp"
android:hint="@string/confirm_password"
app:endIconMode="password_toggle"
app:layout_constraintTop_toBottomOf="@id/tilPassword">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilSecurityQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/security_question_for_password_reset"
app:layout_constraintTop_toBottomOf="@id/tilConfirmPassword">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etConfirmPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionNext"
android:inputType="number"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etSecurityQuestion"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilSecurityQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
android:layout_marginTop="16dp"
android:hint="@string/security_question_for_password_reset"
app:layout_constraintTop_toBottomOf="@id/tilConfirmPassword">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilSecurityAnswer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/security_answer"
app:layout_constraintTop_toBottomOf="@id/tilSecurityQuestion">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etSecurityQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etSecurityAnswer"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilSecurityAnswer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
android:layout_marginTop="16dp"
android:hint="@string/security_answer"
app:layout_constraintTop_toBottomOf="@id/tilSecurityQuestion">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSavePassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:padding="12dp"
android:text="@string/save_password"
app:layout_constraintTop_toBottomOf="@id/tilSecurityAnswer" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etSecurityAnswer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnResetPassword"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/forgot_password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnSavePassword" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSavePassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:padding="12dp"
android:text="@string/save_password"
app:layout_constraintTop_toBottomOf="@id/tilSecurityAnswer" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnResetPassword"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/forgot_password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnSavePassword" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -39,6 +39,13 @@
android:layout_weight="1"
android:id="@+id/folderName"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/selectAllButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_select_all"
android:visibility="gone"
style="@style/Widget.Material3.Button.IconButton"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/menuButton"

View File

@@ -4,6 +4,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<androidx.cardview.widget.CardView

View File

@@ -1,5 +1,5 @@
[versions]
agp = "8.10.1"
agp = "8.11.1"
documentfile = "1.1.0"
exp4j = "0.4.8"
glide = "4.16.0"
@@ -20,6 +20,7 @@ roomRuntime = "2.7.1"
swiperefreshlayout = "1.2.0-beta01"
viewpager = "1.1.0"
zoomage = "1.3.1"
lifecycleProcess = "2.9.2"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -43,6 +44,7 @@ material-color-utilities = { module = "com.google.android.material:material-colo
androidx-gridlayout = { group = "androidx.gridlayout", name = "gridlayout", version.ref = "gridlayout" }
photoview = { module = "com.github.chrisbanes:PhotoView", version.ref = "photoview" }
zoomage = { module = "com.jsibbold:zoomage", version.ref = "zoomage" }
androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "lifecycleProcess" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }

View File

@@ -1,6 +1,6 @@
#Sun Nov 03 19:53:13 IST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

BIN
media/payment_qr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB