This commit is contained in:
Binondi
2024-12-14 21:37:34 +05:30
19 changed files with 482 additions and 246 deletions

View File

@@ -6,13 +6,17 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import devs.org.calculator.utils.FileManager import devs.org.calculator.utils.FileManager
import devs.org.calculator.utils.FileProcessCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class AudioGalleryActivity : BaseGalleryActivity() { class AudioGalleryActivity : BaseGalleryActivity(), FileProcessCallback {
override val fileType = FileManager.FileType.AUDIO override val fileType = FileManager.FileType.AUDIO
private lateinit var pickAudioLauncher: ActivityResultLauncher<Intent> private lateinit var pickAudioLauncher: ActivityResultLauncher<Intent>
private var selectedUri: Uri? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -20,32 +24,43 @@ class AudioGalleryActivity : BaseGalleryActivity() {
pickAudioLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> pickAudioLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) { if (result.resultCode == RESULT_OK) {
val uri = result.data?.data val clipData = result.data?.clipData
if (uri != null) { val uriList = mutableListOf<Uri>()
selectedUri = uri
try { if (clipData != null) {
val file = fileManager.copyFileToHiddenDir(selectedUri!!, fileType) for (i in 0 until clipData.itemCount) {
if (file != null && file.exists()) { val uri = clipData.getItemAt(i).uri
Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() uriList.add(uri)
loadFiles()
} else {
Toast.makeText(this, "Failed to hide file", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
} }
} else { } else {
Toast.makeText(this, "No audio selected", Toast.LENGTH_SHORT).show() result.data?.data?.let { uriList.add(it) } // Single file selected
}
if (uriList.isNotEmpty()) {
lifecycleScope.launch {
FileManager(this@AudioGalleryActivity, this@AudioGalleryActivity).processMultipleFiles(uriList, fileType,this@AudioGalleryActivity )
}
} else {
Toast.makeText(this, "No files selected", Toast.LENGTH_SHORT).show()
} }
} }
} }
} }
override fun onFilesProcessedSuccessfully(copiedFiles: List<File>) {
Toast.makeText(this@AudioGalleryActivity, "${copiedFiles.size} Audios hidden successfully", Toast.LENGTH_SHORT).show()
loadFiles()
}
override fun onFileProcessFailed() {
Toast.makeText(this@AudioGalleryActivity, "Failed to hide Audios", Toast.LENGTH_SHORT).show()
}
private fun setupFabButton() { private fun setupFabButton() {
binding.fabAdd.setOnClickListener { binding.fabAdd.setOnClickListener {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "audio/*" type = "audio/*"
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
@@ -57,4 +72,6 @@ class AudioGalleryActivity : BaseGalleryActivity() {
override fun openPreview() { override fun openPreview() {
// Implement audio preview // Implement audio preview
} }
} }

View File

@@ -22,21 +22,33 @@ abstract class BaseGalleryActivity : AppCompatActivity() {
protected lateinit var binding: ActivityGalleryBinding protected lateinit var binding: ActivityGalleryBinding
protected lateinit var fileManager: FileManager protected lateinit var fileManager: FileManager
protected lateinit var adapter: FileAdapter protected lateinit var adapter: FileAdapter
protected lateinit var files: List<File>
private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest> private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest>
private val storagePermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val granted = permissions.values.all { it }
if (granted || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && Environment.isExternalStorageManager()) {
loadFiles()
} else {
// Handle permission denial case
showPermissionDeniedDialog()
}
}
abstract val fileType: FileManager.FileType abstract val fileType: FileManager.FileType
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setupIntentSenderLauncher() setupIntentSenderLauncher()
checkPermissions()
binding = ActivityGalleryBinding.inflate(layoutInflater) binding = ActivityGalleryBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
fileManager = FileManager(this, this) fileManager = FileManager(this, this)
setupRecyclerView() setupRecyclerView()
loadFiles() checkPermissionsAndLoadFiles()
} }
private fun setupIntentSenderLauncher() { private fun setupIntentSenderLauncher() {
@@ -51,51 +63,54 @@ abstract class BaseGalleryActivity : AppCompatActivity() {
private fun setupRecyclerView() { private fun setupRecyclerView() {
binding.recyclerView.layoutManager = GridLayoutManager(this, 3) binding.recyclerView.layoutManager = GridLayoutManager(this, 3)
adapter = FileAdapter( adapter = FileAdapter(fileType, this, this)
fileType,
this, this
)
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
} }
protected fun loadFiles() { private fun checkPermissionsAndLoadFiles() {
val files = fileManager.getFilesInHiddenDir(fileType) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
.addCategory("android.intent.category.DEFAULT")
.setData(Uri.parse("package:${applicationContext.packageName}"))
startActivityForResult(intent, 2296)
} else {
loadFiles()
}
} else {
val permissions = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
if (permissions.any { checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED }) {
storagePermissionLauncher.launch(permissions)
} else {
loadFiles()
}
}
}
protected open fun loadFiles() {
files = fileManager.getFilesInHiddenDir(fileType)
adapter.submitList(files) adapter.submitList(files)
adapter.notifyDataSetChanged() }
override fun onResume() {
super.onResume()
loadFiles()
} }
abstract fun openPreview() abstract fun openPreview()
private fun checkPermissions() { private fun showPermissionDeniedDialog() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Show a dialog or a message informing the user about the importance of permissions
if (!Environment.isExternalStorageManager()) {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse("package:${applicationContext.packageName}")
startActivityForResult(intent, 2296)
}
} else {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
),
1001
)
}
}
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 2296) { if (requestCode == 2296 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Environment.isExternalStorageManager()) {
if (Environment.isExternalStorageManager()) { loadFiles()
// Permission granted
loadFiles()
}
} }
} }
} }

View File

@@ -6,51 +6,69 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import devs.org.calculator.activities.AudioGalleryActivity
import devs.org.calculator.utils.FileManager import devs.org.calculator.utils.FileManager
import devs.org.calculator.utils.FileProcessCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class DocumentsActivity : BaseGalleryActivity() { class DocumentsActivity : BaseGalleryActivity(), FileProcessCallback {
override val fileType = FileManager.FileType.DOCUMENT override val fileType = FileManager.FileType.DOCUMENT
private lateinit var pickDocumentLauncher: ActivityResultLauncher<Intent> private lateinit var pickLauncher: ActivityResultLauncher<Intent>
private var selectedUri: Uri? = null private var selectedUri: Uri? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setupFabButton() setupFabButton()
pickDocumentLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> pickLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) { if (result.resultCode == RESULT_OK) {
val uri = result.data?.data val clipData = result.data?.clipData
if (uri != null) { val uriList = mutableListOf<Uri>()
selectedUri = uri
try { if (clipData != null) {
val file = fileManager.copyFileToHiddenDir(selectedUri!!, fileType) for (i in 0 until clipData.itemCount) {
if (file != null && file.exists()) { val uri = clipData.getItemAt(i).uri
Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() uriList.add(uri)
loadFiles()
} else {
Toast.makeText(this, "Failed to hide file", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
} }
} else { } else {
Toast.makeText(this, "No document selected", Toast.LENGTH_SHORT).show() result.data?.data?.let { uriList.add(it) } // Single file selected
}
if (uriList.isNotEmpty()) {
lifecycleScope.launch {
FileManager(this@DocumentsActivity, this@DocumentsActivity).processMultipleFiles(uriList, fileType,this@DocumentsActivity )
}
} else {
Toast.makeText(this, "No files selected", Toast.LENGTH_SHORT).show()
} }
} }
} }
} }
override fun onFilesProcessedSuccessfully(copiedFiles: List<File>) {
Toast.makeText(this@DocumentsActivity, "${copiedFiles.size} Documents hidden successfully", Toast.LENGTH_SHORT).show()
loadFiles()
}
override fun onFileProcessFailed() {
Toast.makeText(this@DocumentsActivity, "Failed to hide Documents", Toast.LENGTH_SHORT).show()
}
private fun setupFabButton() { private fun setupFabButton() {
binding.fabAdd.setOnClickListener { binding.fabAdd.setOnClickListener {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "*/*" type = "*/*"
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
} }
pickDocumentLauncher.launch(intent) pickLauncher.launch(intent)
} }
} }

View File

@@ -1,28 +1,33 @@
package devs.org.calculator.activities package devs.org.calculator.activities
import android.app.RecoverableSecurityException
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.provider.MediaStore
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import devs.org.calculator.utils.FileManager import devs.org.calculator.utils.FileManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import android.Manifest
import devs.org.calculator.activities.AudioGalleryActivity
import devs.org.calculator.utils.FileProcessCallback
class ImageGalleryActivity : BaseGalleryActivity() { class ImageGalleryActivity : BaseGalleryActivity(), FileProcessCallback {
override val fileType = FileManager.FileType.IMAGE override val fileType = FileManager.FileType.IMAGE
private val STORAGE_PERMISSION_CODE = 100
private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest> private lateinit var intentSenderLauncher: ActivityResultLauncher<IntentSenderRequest>
private var selectedImageUri: Uri? = null
private lateinit var pickImageLauncher: ActivityResultLauncher<Intent> private lateinit var pickImageLauncher: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -32,36 +37,48 @@ class ImageGalleryActivity : BaseGalleryActivity() {
intentSenderLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ intentSenderLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){
if (it.resultCode == RESULT_OK){ if (it.resultCode == RESULT_OK){
Toast.makeText(this, "Photo Deleted Successfully", Toast.LENGTH_SHORT).show() // Toast.makeText(this, "Photo Deleted Successfully", Toast.LENGTH_SHORT).show()
}else{ }else{
Toast.makeText(this, "Failed to delete photo", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Failed to hide/unhide photo", Toast.LENGTH_SHORT).show()
} }
} }
pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) { if (result.resultCode == RESULT_OK) {
val uri = result.data?.data val clipData = result.data?.clipData
if (uri != null) { val uriList = mutableListOf<Uri>()
selectedImageUri = uri
try { if (clipData != null) {
val file = fileManager.copyFileToHiddenDir(selectedImageUri!!, fileType) for (i in 0 until clipData.itemCount) {
if (file != null && file.exists()) { val uri = clipData.getItemAt(i).uri
Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() uriList.add(uri)
loadFiles()
} else {
Toast.makeText(this, "Failed to hide file", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
} }
} else { } else {
Toast.makeText(this, "No image selected", Toast.LENGTH_SHORT).show() result.data?.data?.let { uriList.add(it) } // Single file selected
}
if (uriList.isNotEmpty()) {
lifecycleScope.launch {
FileManager(this@ImageGalleryActivity, this@ImageGalleryActivity)
.processMultipleFiles(uriList, fileType,this@ImageGalleryActivity )
}
} else {
Toast.makeText(this, "No files selected", Toast.LENGTH_SHORT).show()
} }
} }
} }
askPermissiom() askPermissiom()
} }
override fun onFilesProcessedSuccessfully(copiedFiles: List<File>) {
Toast.makeText(this@ImageGalleryActivity, "${copiedFiles.size} Images hidden successfully", Toast.LENGTH_SHORT).show()
loadFiles()
}
override fun onFileProcessFailed() {
Toast.makeText(this@ImageGalleryActivity, "Failed to hide images", Toast.LENGTH_SHORT).show()
}
private fun setupIntentSenderLauncher() { private fun setupIntentSenderLauncher() {
intentSenderLauncher = registerForActivityResult( intentSenderLauncher = registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult() ActivityResultContracts.StartIntentSenderForResult()
@@ -80,7 +97,45 @@ class ImageGalleryActivity : BaseGalleryActivity() {
} }
} }
else { else {
Toast.makeText(this, "Android Version Lower", Toast.LENGTH_SHORT).show() checkAndRequestStoragePermission()
}
}
private fun checkAndRequestStoragePermission() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
),
STORAGE_PERMISSION_CODE
)
} else {
//storage permission granted
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == STORAGE_PERMISSION_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Storage permissions granted", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "Storage permissions denied", Toast.LENGTH_SHORT).show()
}
} }
} }
@@ -89,6 +144,7 @@ class ImageGalleryActivity : BaseGalleryActivity() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "image/*" type = "image/*"
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)

View File

@@ -57,6 +57,7 @@ class MainActivity : AppCompatActivity() {
binding.btnDot.setOnClickListener { addDecimal() } binding.btnDot.setOnClickListener { addDecimal() }
binding.btnEquals.setOnClickListener { calculateResult() } binding.btnEquals.setOnClickListener { calculateResult() }
binding.btnPercent.setOnClickListener { calculatePercentage() } binding.btnPercent.setOnClickListener { calculatePercentage() }
binding.cut.setOnClickListener { cutNumbers() }
} }
private fun launchBaseDirectoryPicker() { private fun launchBaseDirectoryPicker() {
@@ -162,11 +163,23 @@ class MainActivity : AppCompatActivity() {
hasDecimal = currentExpression.contains(".") hasDecimal = currentExpression.contains(".")
updateDisplay() updateDisplay()
} catch (e: Exception) { } catch (e: Exception) {
binding.display.text = "Error" binding.display.text = "Invalid Value"
} }
} }
private fun updateDisplay() { private fun updateDisplay() {
binding.display.text = currentExpression binding.display.text = currentExpression
} }
private fun cutNumbers() {
if (currentExpression.isNotEmpty()){
if (currentExpression.length == 1){
currentExpression = currentExpression.substring(0, currentExpression.length - 1)
currentExpression = "0"
}else currentExpression = currentExpression.substring(0, currentExpression.length - 1)
}else currentExpression = "0"
updateDisplay()
}
} }

View File

@@ -1,14 +1,15 @@
package devs.org.calculator.activities package devs.org.calculator.activities
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import devs.org.calculator.adapters.ImagePreviewAdapter import devs.org.calculator.adapters.ImagePreviewAdapter
import devs.org.calculator.databinding.ActivityPreviewBinding import devs.org.calculator.databinding.ActivityPreviewBinding
import devs.org.calculator.utils.DialogUtil import devs.org.calculator.utils.DialogUtil
import devs.org.calculator.utils.FileManager import devs.org.calculator.utils.FileManager
import kotlinx.coroutines.launch
import java.io.File import java.io.File
class PreviewActivity : AppCompatActivity() { class PreviewActivity : AppCompatActivity() {
@@ -29,70 +30,102 @@ class PreviewActivity : AppCompatActivity() {
fileManager = FileManager(this, this) fileManager = FileManager(this, this)
currentPosition = intent.getIntExtra("position", 0) currentPosition = intent.getIntExtra("position", 0)
type = intent.getStringExtra("type").toString() type = intent.getStringExtra("type").toString()
clickListeners() setupFileType()
when(type){
"IMAGE" ->{
filetype = FileManager.FileType.IMAGE
binding.title.text = "Preview Images"
}
"VIDEO" ->{
filetype = FileManager.FileType.VIDEO
binding.title.text = "Preview Videos"
}
"AUDIO" ->{
filetype = FileManager.FileType.AUDIO
binding.title.text = "Preview Audios"
}
else -> {
filetype = FileManager.FileType.DOCUMENT
binding.title.text = "Preview Docomnts"
}
}
files = fileManager.getFilesInHiddenDir(filetype) files = fileManager.getFilesInHiddenDir(filetype)
setupImagePreview() setupImagePreview()
clickListeners()
} }
private fun clickListeners() { private fun setupFileType() {
binding.delete.setOnClickListener{ when (type) {
var fileUri = FileManager.FileManager().getContentUri(this, files[binding.viewPager.currentItem]) "IMAGE" -> {
if (fileUri != null) { filetype = FileManager.FileType.IMAGE
DialogUtil(this, this).showMaterialDialog( binding.title.text = "Preview Images"
"Delete File", }
"Are you sure you want to delete this file ?", "VIDEO" -> {
"Delete", filetype = FileManager.FileType.VIDEO
"Cancel", binding.title.text = "Preview Videos"
fileUri!! }
) "AUDIO" -> {
filetype = FileManager.FileType.AUDIO
binding.title.text = "Preview Audios"
}
else -> {
filetype = FileManager.FileType.DOCUMENT
binding.title.text = "Preview Documents"
} }
}
binding.unHide.setOnClickListener{
DialogUtil(this, this).showMaterialDialog("Unhide File","Are you sure you want to unhide this file ?", "Unhide", "Cancel")
} }
} }
private fun setupImagePreview() { private fun setupImagePreview() {
adapter = ImagePreviewAdapter(this, files,filetype) adapter = ImagePreviewAdapter(this, filetype)
adapter.images = files // Set initial data
binding.viewPager.adapter = adapter binding.viewPager.adapter = adapter
val fileUri = Uri.fromFile(files[currentPosition])
val filesName = FileManager.FileName(this).getFileNameFromUri(fileUri!!).toString()
binding.viewPager.setCurrentItem(currentPosition, false) binding.viewPager.setCurrentItem(currentPosition, false)
val fileUri = Uri.fromFile(files[currentPosition])
val fileName = FileManager.FileName(this).getFileNameFromUri(fileUri).toString()
binding.title.text = fileName
}
private fun clickListeners() {
binding.delete.setOnClickListener {
val fileUri = FileManager.FileManager().getContentUri(this, files[binding.viewPager.currentItem])
if (fileUri != null) {
MaterialAlertDialogBuilder(this)
.setTitle("Delete File")
.setMessage("Are you sure you want to Delete this file?")
.setPositiveButton("Delete") { dialog, _ ->
lifecycleScope.launch {
FileManager(this@PreviewActivity, this@PreviewActivity).deletePhotoFromExternalStorage(fileUri)
removeFileFromList(binding.viewPager.currentItem)
}
dialog.dismiss()
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
.show()
}
}
binding.unHide.setOnClickListener {
val fileUri = FileManager.FileManager().getContentUri(this, files[binding.viewPager.currentItem])
if (fileUri != null) {
MaterialAlertDialogBuilder(this)
.setTitle("Unhide File")
.setMessage("Are you sure you want to Unhide this file?")
.setPositiveButton("Unhide") { dialog, _ ->
lifecycleScope.launch {
FileManager(this@PreviewActivity, this@PreviewActivity).copyFileToNormalDir(fileUri)
removeFileFromList(binding.viewPager.currentItem)
}
dialog.dismiss()
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
.show()
}
}
}
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.isNotEmpty()) finish()
} }
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
onBackPressed() onBackPressed()
return true return true
} }
} }

View File

@@ -6,12 +6,18 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import devs.org.calculator.activities.ImageGalleryActivity
import devs.org.calculator.utils.FileManager import devs.org.calculator.utils.FileManager
import devs.org.calculator.utils.FileProcessCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class VideoGalleryActivity : BaseGalleryActivity() { class VideoGalleryActivity : BaseGalleryActivity(), FileProcessCallback {
override val fileType = FileManager.FileType.VIDEO override val fileType = FileManager.FileType.VIDEO
private lateinit var pickVideoLauncher: ActivityResultLauncher<Intent> private lateinit var pickLauncher: ActivityResultLauncher<Intent>
private var selectedUri: Uri? = null private var selectedUri: Uri? = null
@@ -19,39 +25,52 @@ class VideoGalleryActivity : BaseGalleryActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setupFabButton() setupFabButton()
pickVideoLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> pickLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) { if (result.resultCode == RESULT_OK) {
val uri = result.data?.data val clipData = result.data?.clipData
if (uri != null) { val uriList = mutableListOf<Uri>()
selectedUri = uri
try { if (clipData != null) {
val file = fileManager.copyFileToHiddenDir(selectedUri!!, fileType) for (i in 0 until clipData.itemCount) {
if (file != null && file.exists()) { val uri = clipData.getItemAt(i).uri
Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() uriList.add(uri)
loadFiles()
} else {
Toast.makeText(this, "Failed to hide file", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
} }
} else { } else {
Toast.makeText(this, "No video selected", Toast.LENGTH_SHORT).show() result.data?.data?.let { uriList.add(it) } // Single file selected
}
if (uriList.isNotEmpty()) {
lifecycleScope.launch {
FileManager(this@VideoGalleryActivity, this@VideoGalleryActivity)
.processMultipleFiles(uriList, fileType,this@VideoGalleryActivity )
}
} else {
Toast.makeText(this, "No files selected", Toast.LENGTH_SHORT).show()
} }
} }
} }
} }
override fun onFilesProcessedSuccessfully(copiedFiles: List<File>) {
Toast.makeText(this@VideoGalleryActivity, "${copiedFiles.size} Videos hidden successfully", Toast.LENGTH_SHORT).show()
loadFiles()
}
override fun onFileProcessFailed() {
Toast.makeText(this@VideoGalleryActivity, "Failed to hide videos", Toast.LENGTH_SHORT).show()
}
private fun setupFabButton() { private fun setupFabButton() {
binding.fabAdd.setOnClickListener { binding.fabAdd.setOnClickListener {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "video/*" type = "video/*"
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
} }
pickVideoLauncher.launch(intent) pickLauncher.launch(intent)
} }
} }

View File

@@ -86,7 +86,7 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
MaterialAlertDialogBuilder(context) MaterialAlertDialogBuilder(context)
.setTitle("Details") .setTitle("Details")
.setMessage("File Name: $filesName\\n\\nYou can delete or unghide this file\", \"Delete") .setMessage("File Name: $filesName\n\nYou can delete or Unhide this file.")
.setPositiveButton("Delete") { dialog, _ -> .setPositiveButton("Delete") { dialog, _ ->
// Handle positive button click // Handle positive button click
lifecycleOwner.lifecycleScope.launch{ lifecycleOwner.lifecycleScope.launch{
@@ -100,7 +100,11 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
} }
.setNegativeButton("Unhide") { dialog, _ -> .setNegativeButton("Unhide") { dialog, _ ->
// Handle negative button click // Handle negative button click
FileManager(context, context as LifecycleOwner).copyFileToNormalDir(fileUri)
val currentList = currentList.toMutableList()
currentList.remove(file)
submitList(currentList)
dialog.dismiss()
dialog.dismiss() dialog.dismiss()
} }
.show() .show()
@@ -110,11 +114,6 @@ class FileAdapter(private val fileType: FileManager.FileType, var context: Conte
} }
} }
fun reloadList(file: File){
val currentList = currentList.toMutableList()
currentList.remove(file)
submitList(currentList)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FileViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FileViewHolder {

View File

@@ -6,28 +6,35 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.MediaController import android.widget.MediaController
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import devs.org.calculator.adapters.FileAdapter.FileDiffCallback
import devs.org.calculator.databinding.ViewpagerItemsBinding import devs.org.calculator.databinding.ViewpagerItemsBinding
import devs.org.calculator.utils.FileManager import devs.org.calculator.utils.FileManager
import java.io.File import java.io.File
class ImagePreviewAdapter( class ImagePreviewAdapter(
private val context: Context, private val context: Context,
private val images: List<File>,
private var fileType: FileManager.FileType private var fileType: FileManager.FileType
) : RecyclerView.Adapter<ImagePreviewAdapter.ImageViewHolder>() { ) : RecyclerView.Adapter<ImagePreviewAdapter.ImageViewHolder>() {
// Use AsyncListDiffer for managing the list
private val differ = AsyncListDiffer(this, FileDiffCallback())
// Expose data management through differ
var images: List<File>
get() = differ.currentList
set(value) = differ.submitList(value)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val binding = ViewpagerItemsBinding.inflate(LayoutInflater.from(context), parent, false val binding = ViewpagerItemsBinding.inflate(LayoutInflater.from(context), parent, false)
)
return ImageViewHolder(binding) return ImageViewHolder(binding)
} }
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) { override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val imageUrl = images[position] val imageUrl = images[position]
holder.bind(imageUrl) holder.bind(imageUrl)
} }
override fun getItemCount(): Int = images.size override fun getItemCount(): Int = images.size
@@ -39,31 +46,27 @@ class ImagePreviewAdapter(
binding.imageView.visibility = View.GONE binding.imageView.visibility = View.GONE
binding.videoView.visibility = View.VISIBLE binding.videoView.visibility = View.VISIBLE
// Set up the VideoView with the current video file
val videoUri = Uri.fromFile(file) val videoUri = Uri.fromFile(file)
binding.videoView.setVideoURI(videoUri) binding.videoView.setVideoURI(videoUri)
binding.videoView.start() binding.videoView.start()
// Create and attach MediaController
val mediaController = MediaController(context) val mediaController = MediaController(context)
mediaController.setAnchorView(binding.videoView) mediaController.setAnchorView(binding.videoView)
binding.videoView.setMediaController(mediaController) binding.videoView.setMediaController(mediaController)
// Handle the "Next" button logic
mediaController.setPrevNextListeners( mediaController.setPrevNextListeners(
{ // Next button clicked {
val nextPosition = (adapterPosition + 1) % images.size // Loop to start if last val nextPosition = (adapterPosition + 1) % images.size
playVideoAtPosition(nextPosition) playVideoAtPosition(nextPosition)
}, },
{ // Previous button clicked {
val prevPosition = if (adapterPosition - 1 < 0) images.size - 1 else adapterPosition - 1 val prevPosition = if (adapterPosition - 1 < 0) images.size - 1 else adapterPosition - 1
playVideoAtPosition(prevPosition) playVideoAtPosition(prevPosition)
} }
) )
// Play next video automatically when the current one finishes
binding.videoView.setOnCompletionListener { binding.videoView.setOnCompletionListener {
val nextPosition = (adapterPosition + 1) % images.size // Loop to start if last val nextPosition = (adapterPosition + 1) % images.size
playVideoAtPosition(nextPosition) playVideoAtPosition(nextPosition)
} }
} }
@@ -92,7 +95,5 @@ class ImagePreviewAdapter(
} }
} }
} }
} }

View File

@@ -74,7 +74,7 @@ class DialogUtil(private val context: Context, private var lifecycleOwner: Lifec
val deleted = documentFile.delete() val deleted = documentFile.delete()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (deleted) { if (deleted) {
Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show() // Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show()
} else { } else {
Toast.makeText(context, "Failed to delete file", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Failed to delete file", Toast.LENGTH_SHORT).show()
} }

View File

@@ -6,6 +6,8 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.provider.ContactsContract
import android.provider.ContactsContract.Directory
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.provider.MediaStore import android.provider.MediaStore
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
@@ -15,6 +17,7 @@ import androidx.activity.result.IntentSenderRequest
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import devs.org.calculator.activities.VideoGalleryActivity
import devs.org.calculator.adapters.FileAdapter import devs.org.calculator.adapters.FileAdapter
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -95,6 +98,46 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
null null
} }
} }
fun copyFileToNormalDir(uri: Uri): File? {
return try {
val contentResolver = context.contentResolver
// Get the target directory
val targetDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
targetDir.mkdirs()
// Create target file
val mimeType = contentResolver.getType(uri)
val extension = MimeTypeMap.getSingleton()
.getExtensionFromMimeType(mimeType) ?: ""
val fileName = "${System.currentTimeMillis()}.${extension}"
val targetFile = File(targetDir, fileName)
// Copy file using DocumentFile
contentResolver.openInputStream(uri)?.use { input ->
targetFile.outputStream().use { output ->
input.copyTo(output)
}
}
// Verify copy success
if (!targetFile.exists() || targetFile.length() == 0L) {
throw Exception("File copy failed")
}
// Media scan the new file to hide it
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
mediaScanIntent.data = Uri.fromFile(targetDir)
context.sendBroadcast(mediaScanIntent)
lifecycleOwner.lifecycleScope.launch {
deletePhotoFromExternalStorage(uri)
}
targetFile
} catch (e: Exception) {
e.printStackTrace()
null
}
}
@@ -108,9 +151,9 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
val deleted = documentFile.delete() val deleted = documentFile.delete()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (deleted) { if (deleted) {
Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show() // Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show()
} else { } else {
Toast.makeText(context, "Failed to delete file", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Failed to hide/unhide file", Toast.LENGTH_SHORT).show()
} }
} }
return@withContext return@withContext
@@ -120,7 +163,7 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
try { try {
context.contentResolver.delete(photoUri, null, null) context.contentResolver.delete(photoUri, null, null)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show() // Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show()
} }
} catch (e: SecurityException) { } catch (e: SecurityException) {
// Handle security exception for Android 10 and above // Handle security exception for Android 10 and above
@@ -145,7 +188,7 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
Toast.makeText( Toast.makeText(
context, context,
"Error deleting file: ${e.message}", "Error hiding/unhiding file: ${e.message}",
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} }
@@ -196,6 +239,31 @@ class FileManager(private val context: Context, private val lifecycleOwner: Life
} }
suspend fun processMultipleFiles(
uriList: List<Uri>,
fileType: FileType,
callback: FileProcessCallback
) {
withContext(Dispatchers.IO) {
val copiedFiles = mutableListOf<File>()
for (uri in uriList) {
try {
val file = copyFileToHiddenDir(uri, fileType)
file?.let { copiedFiles.add(it) }
} catch (e: Exception) {
e.printStackTrace()
}
}
withContext(Dispatchers.Main) {
if (copiedFiles.isNotEmpty()) {
callback.onFilesProcessedSuccessfully(copiedFiles)
} else {
callback.onFileProcessFailed()
}
}
}
}
enum class FileType(val dirName: String) { enum class FileType(val dirName: String) {

View File

@@ -0,0 +1,8 @@
package devs.org.calculator.utils
import java.io.File
interface FileProcessCallback {
fun onFilesProcessedSuccessfully(copiedFiles: List<File>)
fun onFileProcessFailed()
}

View File

@@ -0,0 +1,15 @@
<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="#00000000"
android:pathData="M7.7,6.36L3.533,11.36C3.224,11.731 3.224,12.269 3.533,12.64L7.7,17.64C7.89,17.868 8.172,18 8.468,18H18C19.657,18 21,16.657 21,15V9C21,7.343 19.657,6 18,6H8.468C8.172,6 7.89,6.132 7.7,6.36Z"
android:strokeColor="@color/textColor" android:strokeLineCap="round"
android:strokeLineJoin="round" android:strokeWidth="2"/>
<path android:fillColor="#00000000"
android:pathData="M15,10L13,12M13,12L11,14M13,12L11,10M13,12L15,14"
android:strokeColor="@color/textColor"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="2"/>
</vector>

View File

@@ -47,18 +47,6 @@
app:cornerRadius="15dp" app:cornerRadius="15dp"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"/> style="@style/Widget.MaterialComponents.Button.OutlinedButton"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnParentheses"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:textSize="30sp"
android:layout_margin="4dp"
android:text="( )"
app:cornerRadius="15dp"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"/>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btnPercent" android:id="@+id/btnPercent"
android:layout_width="0dp" android:layout_width="0dp"
@@ -81,8 +69,20 @@
android:layout_margin="4dp" android:layout_margin="4dp"
android:text="÷" android:text="÷"
app:cornerRadius="15dp" app:cornerRadius="15dp"
style="@style/Widget.MaterialComponents.Button"/> style="@style/Widget.MaterialComponents.Button.OutlinedButton"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/cut"
android:layout_height="0dp"
android:layout_width="0dp"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:textSize="30sp"
android:layout_margin="4dp"
app:icon="@drawable/backspace"
app:iconSize="30dp"
app:cornerRadius="15dp"/>
<!-- Row 2 --> <!-- Row 2 -->
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn7" android:id="@+id/btn7"

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<!-- Material You dynamic colors -->
<color name="primary">@android:color/system_accent1_600</color>
<color name="on_primary">@android:color/system_accent1_0</color>
<color name="primary_container">@android:color/system_accent1_100</color>
<color name="on_primary_container">@android:color/system_accent1_900</color>
<color name="secondary">@android:color/system_accent2_600</color>
<color name="on_secondary">@android:color/system_accent2_0</color>
<color name="secondary_container">@android:color/system_accent2_100</color>
<color name="on_secondary_container">@android:color/system_accent2_900</color>
<color name="surface">@android:color/system_neutral1_50</color>
<color name="on_surface">@android:color/system_neutral1_900</color>
<color name="textColor">#ffffff</color>
</resources>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.Theme.Calculator" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Primary brand color -->
<item name="colorPrimary">@android:color/system_accent1_600</item>
<item name="colorPrimaryVariant">@android:color/system_accent1_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="fontFamily">@font/ubuntu_regular</item>
<!-- Secondary brand color -->
<item name="colorSecondary">@android:color/system_accent2_600</item>
<item name="colorSecondaryVariant">@android:color/system_accent2_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color -->
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<!-- Enable window decor fitting -->
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar">true</item>
</style>
</resources>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Base.Theme.Calculator" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Primary brand color -->
<item name="colorPrimary">@android:color/system_accent1_600</item>
<item name="colorPrimaryVariant">@android:color/system_accent1_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color -->
<item name="colorSecondary">@android:color/system_accent2_600</item>
<item name="colorSecondaryVariant">@android:color/system_accent2_700</item>
<item name="colorOnSecondary">@color/black</item>
<item name="fontFamily">@font/ubuntu_regular</item>
<!-- Status bar color -->
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<!-- Enable window decor fitting -->
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar">true</item>
</style>
</resources>

View File

@@ -16,4 +16,5 @@
<color name="surface">@android:color/system_neutral1_50</color> <color name="surface">@android:color/system_neutral1_50</color>
<color name="on_surface">@android:color/system_neutral1_900</color> <color name="on_surface">@android:color/system_neutral1_900</color>
<color name="textColor">#000000</color>
</resources> </resources>

View File

@@ -5,6 +5,7 @@
<item name="colorPrimary">@android:color/system_accent1_600</item> <item name="colorPrimary">@android:color/system_accent1_600</item>
<item name="colorPrimaryVariant">@android:color/system_accent1_700</item> <item name="colorPrimaryVariant">@android:color/system_accent1_700</item>
<item name="colorOnPrimary">@color/white</item> <item name="colorOnPrimary">@color/white</item>
<item name="android:textColor"></item>
<item name="fontFamily">@font/ubuntu_regular</item> <item name="fontFamily">@font/ubuntu_regular</item>
<!-- Secondary brand color --> <!-- Secondary brand color -->