From ce95aceed5a3afb9e29f2db838ad52328967eaa5 Mon Sep 17 00:00:00 2001 From: Binondi Date: Fri, 13 Dec 2024 23:26:02 +0530 Subject: [PATCH] First commit --- .gitignore | 15 + .idea/.gitignore | 3 + .idea/.name | 1 + .idea/appInsightsSettings.xml | 26 ++ .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 10 + .idea/gradle.xml | 20 ++ .idea/kotlinc.xml | 6 + .idea/material_theme_project_new.xml | 18 ++ .idea/migrations.xml | 10 + .idea/misc.xml | 9 + .idea/render.experimental.xml | 6 + .idea/runConfigurations.xml | 17 ++ .idea/vcs.xml | 6 + app/.gitignore | 1 + app/build.gradle.kts | 58 ++++ app/proguard-rules.pro | 21 ++ .../org/calculator/ExampleInstrumentedTest.kt | 24 ++ app/src/main/AndroidManifest.xml | 65 +++++ app/src/main/ic_launcher-playstore.png | Bin 0 -> 30272 bytes .../java/devs/org/calculator/CalculatorApp.kt | 12 + .../activities/AudioGalleryActivity.kt | 60 ++++ .../activities/BaseGalleryActivity.kt | 100 +++++++ .../activities/DocumentsActivity.kt | 60 ++++ .../activities/HiddenVaultActivity.kt | 36 +++ .../activities/ImageGalleryActivity.kt | 166 +++++++++++ .../org/calculator/activities/MainActivity.kt | 172 +++++++++++ .../calculator/activities/PreviewActivity.kt | 51 ++++ .../activities/SetupPasswordActivity.kt | 37 +++ .../calculator/activities/SplashActivity.kt | 32 ++ .../activities/VideoGalleryActivity.kt | 65 +++++ .../org/calculator/adapters/FileAdapter.kt | 73 +++++ .../adapters/ImagePreviewAdapter.kt | 36 +++ .../devs/org/calculator/utils/FileManager.kt | 195 +++++++++++++ .../devs/org/calculator/utils/PrefsUtil.kt | 46 +++ .../org/calculator/utils/SecurityUtils.kt | 64 ++++ .../calculator/utils/StoragePermissionUtil.kt | 68 +++++ .../org/calculator/views/SquareImageView.kt | 16 + app/src/main/res/drawable/ic_audio.xml | 9 + app/src/main/res/drawable/ic_document.xml | 9 + app/src/main/res/drawable/ic_file.xml | 9 + app/src/main/res/drawable/ic_image.xml | 9 + .../res/drawable/ic_launcher_background.xml | 170 +++++++++++ .../res/drawable/ic_launcher_foreground.xml | 30 ++ .../res/layout/activity_audio_gallery.xml | 10 + .../main/res/layout/activity_documents.xml | 10 + app/src/main/res/layout/activity_gallery.xml | 23 ++ .../main/res/layout/activity_gallery_base.xml | 22 ++ .../main/res/layout/activity_hidden_vault.xml | 121 ++++++++ .../res/layout/activity_image_gallery.xml | 10 + app/src/main/res/layout/activity_main.xml | 273 ++++++++++++++++++ app/src/main/res/layout/activity_preview.xml | 19 ++ .../res/layout/activity_setup_password.xml | 108 +++++++ app/src/main/res/layout/activity_splash.xml | 19 ++ .../res/layout/activity_video_gallery.xml | 10 + app/src/main/res/layout/item_file.xml | 15 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1518 bytes .../mipmap-hdpi/ic_launcher_background.webp | Bin 0 -> 1136 bytes .../mipmap-hdpi/ic_launcher_foreground.webp | Bin 0 -> 600 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 3446 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 1224 bytes .../mipmap-mdpi/ic_launcher_background.webp | Bin 0 -> 1078 bytes .../mipmap-mdpi/ic_launcher_foreground.webp | Bin 0 -> 444 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 2242 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 2242 bytes .../mipmap-xhdpi/ic_launcher_background.webp | Bin 0 -> 1998 bytes .../mipmap-xhdpi/ic_launcher_foreground.webp | Bin 0 -> 728 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 4440 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2952 bytes .../mipmap-xxhdpi/ic_launcher_background.webp | Bin 0 -> 3792 bytes .../mipmap-xxhdpi/ic_launcher_foreground.webp | Bin 0 -> 1048 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 6782 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3644 bytes .../ic_launcher_background.webp | Bin 0 -> 3910 bytes .../ic_launcher_foreground.webp | Bin 0 -> 1498 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 9012 bytes app/src/main/res/values-night/themes.xml | 22 ++ app/src/main/res/values/colors.xml | 19 ++ app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/themes.xml | 24 ++ app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 ++ .../devs/org/calculator/ExampleUnitTest.kt | 17 ++ build.gradle.kts | 5 + gradle.properties | 23 ++ gradle/libs.versions.toml | 30 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++++++++ gradlew.bat | 89 ++++++ settings.gradle.kts | 24 ++ 93 files changed, 2976 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/appInsightsSettings.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/kotlinc.xml create mode 100644 .idea/material_theme_project_new.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/render.experimental.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/devs/org/calculator/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/java/devs/org/calculator/CalculatorApp.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/AudioGalleryActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/BaseGalleryActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/DocumentsActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/HiddenVaultActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/ImageGalleryActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/MainActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/PreviewActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/SetupPasswordActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/SplashActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/activities/VideoGalleryActivity.kt create mode 100644 app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt create mode 100644 app/src/main/java/devs/org/calculator/adapters/ImagePreviewAdapter.kt create mode 100644 app/src/main/java/devs/org/calculator/utils/FileManager.kt create mode 100644 app/src/main/java/devs/org/calculator/utils/PrefsUtil.kt create mode 100644 app/src/main/java/devs/org/calculator/utils/SecurityUtils.kt create mode 100644 app/src/main/java/devs/org/calculator/utils/StoragePermissionUtil.kt create mode 100644 app/src/main/java/devs/org/calculator/views/SquareImageView.kt create mode 100644 app/src/main/res/drawable/ic_audio.xml create mode 100644 app/src/main/res/drawable/ic_document.xml create mode 100644 app/src/main/res/drawable/ic_file.xml create mode 100644 app/src/main/res/drawable/ic_image.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/layout/activity_audio_gallery.xml create mode 100644 app/src/main/res/layout/activity_documents.xml create mode 100644 app/src/main/res/layout/activity_gallery.xml create mode 100644 app/src/main/res/layout/activity_gallery_base.xml create mode 100644 app/src/main/res/layout/activity_hidden_vault.xml create mode 100644 app/src/main/res/layout/activity_image_gallery.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_preview.xml create mode 100644 app/src/main/res/layout/activity_setup_password.xml create mode 100644 app/src/main/res/layout/activity_splash.xml create mode 100644 app/src/main/res/layout/activity_video_gallery.xml create mode 100644 app/src/main/res/layout/item_file.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_background.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_background.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values-night/themes.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/devs/org/calculator/ExampleUnitTest.kt create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..ca34746 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Calculator \ No newline at end of file diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..371f2e2 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7b3006b --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..148fdd2 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..5b5a15a --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/render.experimental.xml b/.idea/render.experimental.xml new file mode 100644 index 0000000..8ec256a --- /dev/null +++ b/.idea/render.experimental.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..9852b5d --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,58 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "devs.org.calculator" + compileSdk = 35 + + defaultConfig { + applicationId = "devs.org.calculator" + minSdk = 26 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures{ + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.androidx.activity) + implementation(libs.androidx.constraintlayout) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + + //custom dependencies + implementation(libs.exp4j) + implementation("com.github.bumptech.glide:glide:4.16.0") + implementation("androidx.documentfile:documentfile:1.0.1") + implementation("com.github.chrisbanes:PhotoView:2.3.0") + implementation("androidx.viewpager:viewpager:1.0.0") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/devs/org/calculator/ExampleInstrumentedTest.kt b/app/src/androidTest/java/devs/org/calculator/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..c49c79e --- /dev/null +++ b/app/src/androidTest/java/devs/org/calculator/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package devs.org.calculator + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("devs.org.calculator", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c3abffd --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..31ee607a0133a87a32374eb9f069a568f8613fb2 GIT binary patch literal 30272 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 + private var selectedUri: Uri? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupFabButton() + + pickAudioLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + selectedUri = uri + try { + val file = fileManager.copyFileToHiddenDir(selectedUri!!, fileType) + if (file != null && file.exists()) { + Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() + 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 { + Toast.makeText(this, "No audio selected", Toast.LENGTH_SHORT).show() + } + } + } + } + + private fun setupFabButton() { + binding.fabAdd.setOnClickListener { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = "audio/*" + addCategory(Intent.CATEGORY_OPENABLE) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + } + pickAudioLauncher.launch(intent) + } + } + + override fun openPreview(file: File) { + // Implement audio preview + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/BaseGalleryActivity.kt b/app/src/main/java/devs/org/calculator/activities/BaseGalleryActivity.kt new file mode 100644 index 0000000..1e533b9 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/BaseGalleryActivity.kt @@ -0,0 +1,100 @@ +package devs.org.calculator.activities + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Environment +import android.provider.Settings +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.IntentSenderRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.GridLayoutManager +import devs.org.calculator.adapters.FileAdapter +import devs.org.calculator.databinding.ActivityGalleryBinding +import devs.org.calculator.utils.FileManager +import java.io.File + +abstract class BaseGalleryActivity : AppCompatActivity() { + protected lateinit var binding: ActivityGalleryBinding + protected lateinit var fileManager: FileManager + protected lateinit var adapter: FileAdapter + + private lateinit var intentSenderLauncher: ActivityResultLauncher + + abstract val fileType: FileManager.FileType + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupIntentSenderLauncher() + checkPermissions() + binding = ActivityGalleryBinding.inflate(layoutInflater) + setContentView(binding.root) + + fileManager = FileManager(this, this) + setupRecyclerView() + loadFiles() + } + + private fun setupIntentSenderLauncher() { + intentSenderLauncher = registerForActivityResult( + ActivityResultContracts.StartIntentSenderForResult() + ) { result -> + if (result.resultCode == RESULT_OK) { + loadFiles() // Refresh the list after deletion + } + } + } + + private fun setupRecyclerView() { + binding.recyclerView.layoutManager = GridLayoutManager(this, 3) + adapter = FileAdapter( + fileType + ) + binding.recyclerView.adapter = adapter + } + + protected fun loadFiles() { + val files = fileManager.getFilesInHiddenDir(fileType) + adapter.submitList(files) + } + + abstract fun openPreview(file: File) + + private fun checkPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + 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?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == 2296) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (Environment.isExternalStorageManager()) { + // Permission granted + loadFiles() + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/DocumentsActivity.kt b/app/src/main/java/devs/org/calculator/activities/DocumentsActivity.kt new file mode 100644 index 0000000..18378cd --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/DocumentsActivity.kt @@ -0,0 +1,60 @@ +package devs.org.calculator.activities + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import devs.org.calculator.utils.FileManager +import java.io.File + +class DocumentsActivity : BaseGalleryActivity() { + override val fileType = FileManager.FileType.DOCUMENT + private lateinit var pickDocumentLauncher: ActivityResultLauncher + private var selectedUri: Uri? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupFabButton() + + pickDocumentLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + selectedUri = uri + try { + val file = fileManager.copyFileToHiddenDir(selectedUri!!, fileType) + if (file != null && file.exists()) { + Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() + 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 { + Toast.makeText(this, "No document selected", Toast.LENGTH_SHORT).show() + } + } + } + } + + private fun setupFabButton() { + binding.fabAdd.setOnClickListener { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = "*/*" + addCategory(Intent.CATEGORY_OPENABLE) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + } + pickDocumentLauncher.launch(intent) + } + } + + override fun openPreview(file: File) { + // Implement document preview + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/HiddenVaultActivity.kt b/app/src/main/java/devs/org/calculator/activities/HiddenVaultActivity.kt new file mode 100644 index 0000000..e5f0fef --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/HiddenVaultActivity.kt @@ -0,0 +1,36 @@ +package devs.org.calculator.activities + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import devs.org.calculator.databinding.ActivityHiddenVaultBinding +import devs.org.calculator.utils.FileManager + +class HiddenVaultActivity : AppCompatActivity() { + private lateinit var binding: ActivityHiddenVaultBinding + private lateinit var fileManager: FileManager + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityHiddenVaultBinding.inflate(layoutInflater) + setContentView(binding.root) + + fileManager = FileManager(this, this) + setupNavigation() + } + + private fun setupNavigation() { + binding.btnImages.setOnClickListener { + startActivity(Intent(this, ImageGalleryActivity::class.java)) + } + binding.btnVideos.setOnClickListener { + startActivity(Intent(this, VideoGalleryActivity::class.java)) + } + binding.btnAudio.setOnClickListener { + startActivity(Intent(this, AudioGalleryActivity::class.java)) + } + binding.btnDocs.setOnClickListener { + startActivity(Intent(this, DocumentsActivity::class.java)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/ImageGalleryActivity.kt b/app/src/main/java/devs/org/calculator/activities/ImageGalleryActivity.kt new file mode 100644 index 0000000..60ad82a --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/ImageGalleryActivity.kt @@ -0,0 +1,166 @@ +package devs.org.calculator.activities + +import android.app.RecoverableSecurityException +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Environment +import android.provider.MediaStore +import android.provider.Settings +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.IntentSenderRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.documentfile.provider.DocumentFile +import androidx.lifecycle.lifecycleScope +import devs.org.calculator.utils.FileManager +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File + +class ImageGalleryActivity : BaseGalleryActivity() { + override val fileType = FileManager.FileType.IMAGE + + private lateinit var intentSenderLauncher: ActivityResultLauncher + private var selectedImageUri: Uri? = null + private lateinit var pickImageLauncher: ActivityResultLauncher + + private suspend fun deletePhotoFromExternalStorage(photoUri: Uri) { + withContext(Dispatchers.IO) { + try { + // First try to delete using DocumentFile + val documentFile = DocumentFile.fromSingleUri(this@ImageGalleryActivity, photoUri) + if (documentFile?.exists() == true && documentFile.canWrite()) { + val deleted = documentFile.delete() + withContext(Dispatchers.Main) { + if (deleted) { + Toast.makeText(this@ImageGalleryActivity, "File deleted successfully", Toast.LENGTH_SHORT).show() + selectedImageUri = null + } else { + Toast.makeText(this@ImageGalleryActivity, "Failed to delete file", Toast.LENGTH_SHORT).show() + } + } + return@withContext + } + + // If DocumentFile approach fails, try content resolver + try { + contentResolver.delete(photoUri, null, null) + withContext(Dispatchers.Main) { + Toast.makeText(this@ImageGalleryActivity, "File deleted successfully", Toast.LENGTH_SHORT).show() + } + } catch (e: SecurityException) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + val intentSender = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + MediaStore.createDeleteRequest(contentResolver, listOf(photoUri)).intentSender + } + else -> { + val recoverableSecurityException = e as? RecoverableSecurityException + recoverableSecurityException?.userAction?.actionIntent?.intentSender + } + } + intentSender?.let { sender -> + withContext(Dispatchers.Main) { + intentSenderLauncher.launch( + IntentSenderRequest.Builder(sender).build() + ) + } + } + } + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + Toast.makeText( + this@ImageGalleryActivity, + "Error deleting file: ${e.message}", + Toast.LENGTH_LONG + ).show() + } + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupIntentSenderLauncher() + setupFabButton() + + intentSenderLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ + if (it.resultCode == RESULT_OK){ + Toast.makeText(this, "Photo Deleted Successfully", Toast.LENGTH_SHORT).show() + }else{ + Toast.makeText(this, "Failed to delete photo", Toast.LENGTH_SHORT).show() + } + } + + pickImageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + selectedImageUri = uri + try { + val file = fileManager.copyFileToHiddenDir(selectedImageUri!!, fileType) + if (file != null && file.exists()) { + Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() + 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 { + Toast.makeText(this, "No image selected", Toast.LENGTH_SHORT).show() + } + } + } + askPermissiom() + } + + private fun setupIntentSenderLauncher() { + intentSenderLauncher = registerForActivityResult( + ActivityResultContracts.StartIntentSenderForResult() + ) { result -> + if (result.resultCode == RESULT_OK) { + loadFiles() + } + } + } + + private fun askPermissiom() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){ + if (!Environment.isExternalStorageManager()){ + val intent = Intent().setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) + startActivity(intent) + } + } + else { + Toast.makeText(this, "Android Version Lower", Toast.LENGTH_SHORT).show() + } + } + + private fun setupFabButton() { + binding.fabAdd.setOnClickListener { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = "image/*" + addCategory(Intent.CATEGORY_OPENABLE) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + } + pickImageLauncher.launch(intent) + } + } + + override fun openPreview(file: File) { + val intent = Intent(this, PreviewActivity::class.java).apply { + putExtra(PreviewActivity.EXTRA_FILE_PATH, file.absolutePath) + putExtra(PreviewActivity.EXTRA_FILE_TYPE, fileType.name) + } + startActivity(intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/MainActivity.kt b/app/src/main/java/devs/org/calculator/activities/MainActivity.kt new file mode 100644 index 0000000..61f97c4 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/MainActivity.kt @@ -0,0 +1,172 @@ +package devs.org.calculator.activities + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.Log +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.button.MaterialButton +import devs.org.calculator.databinding.ActivityMainBinding +import devs.org.calculator.utils.PrefsUtil +import net.objecthunter.exp4j.ExpressionBuilder + +class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + private var currentExpression = "0" + private var lastWasOperator = false + private var hasDecimal = false + private lateinit var launcher: ActivityResultLauncher + private lateinit var baseDocumentTreeUri: Uri + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + // Initialize ActivityResultLauncher + launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + handleActivityResult(result) + } + + // Ask for base directory picker on startup + + // Number buttons + setupNumberButton(binding.btn0, "0") + setupNumberButton(binding.btn1, "1") + setupNumberButton(binding.btn2, "2") + setupNumberButton(binding.btn3, "3") + setupNumberButton(binding.btn4, "4") + setupNumberButton(binding.btn5, "5") + setupNumberButton(binding.btn6, "6") + setupNumberButton(binding.btn7, "7") + setupNumberButton(binding.btn8, "8") + setupNumberButton(binding.btn9, "9") + + // Operator buttons + setupOperatorButton(binding.btnPlus, "+") + setupOperatorButton(binding.btnMinus, "-") + setupOperatorButton(binding.btnMultiply, "*") + setupOperatorButton(binding.btnDivide, "/") + + // Special buttons + binding.btnClear.setOnClickListener { clearDisplay() } + binding.btnDot.setOnClickListener { addDecimal() } + binding.btnEquals.setOnClickListener { calculateResult() } + binding.btnPercent.setOnClickListener { calculatePercentage() } + } + + private fun launchBaseDirectoryPicker() { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + launcher.launch(intent) + } + + private fun handleActivityResult(result: androidx.activity.result.ActivityResult) { + if (result.resultCode == Activity.RESULT_OK) { + result.data?.data?.let { uri -> + baseDocumentTreeUri = uri + val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + + // Take persistable Uri Permission for future use + contentResolver.takePersistableUriPermission(uri, takeFlags) + + val preferences = getSharedPreferences("com.example.fileutility", Context.MODE_PRIVATE) + preferences.edit().putString("filestorageuri", uri.toString()).apply() + } + } else { + Log.e("FileUtility", "Error occurred or operation cancelled: $result") + } + } + + private fun setupNumberButton(button: MaterialButton, number: String) { + button.setOnClickListener { + if (currentExpression == "0") { + currentExpression = number + } else { + currentExpression += number + } + lastWasOperator = false + updateDisplay() + } + } + + private fun setupOperatorButton(button: MaterialButton, operator: String) { + button.setOnClickListener { + if (!lastWasOperator) { + currentExpression += operator + lastWasOperator = true + hasDecimal = false + } + updateDisplay() + } + } + + private fun clearDisplay() { + currentExpression = "0" + lastWasOperator = false + hasDecimal = false + updateDisplay() + } + + private fun addDecimal() { + if (!hasDecimal && !lastWasOperator) { + currentExpression += "." + hasDecimal = true + updateDisplay() + } + } + + private fun calculatePercentage() { + try { + val value = currentExpression.toDouble() + currentExpression = (value / 100).toString() + updateDisplay() + } catch (e: Exception) { + binding.display.text = "Error" + } + } + + private fun calculateResult() { + // Check for secret code + if (currentExpression == "123456") { // Replace with your desired code + val intent = Intent(this, SetupPasswordActivity::class.java) + intent.putExtra("password", currentExpression) + startActivity(intent) + clearDisplay() + return + } + + // Validate password + if (PrefsUtil(this).validatePassword(currentExpression)) { + val intent = Intent(this, HiddenVaultActivity::class.java) + intent.putExtra("password", currentExpression) + startActivity(intent) + clearDisplay() + return + } + + try { + val expression = ExpressionBuilder(currentExpression).build() + val result = expression.evaluate() + + currentExpression = if (result.toLong().toDouble() == result) { + result.toLong().toString() + } else { + String.format("%.2f", result) + } + + lastWasOperator = false + hasDecimal = currentExpression.contains(".") + updateDisplay() + } catch (e: Exception) { + binding.display.text = "Error" + } + } + + private fun updateDisplay() { + binding.display.text = currentExpression + } +} diff --git a/app/src/main/java/devs/org/calculator/activities/PreviewActivity.kt b/app/src/main/java/devs/org/calculator/activities/PreviewActivity.kt new file mode 100644 index 0000000..e690e58 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/PreviewActivity.kt @@ -0,0 +1,51 @@ +package devs.org.calculator.activities + +import ImagePreviewAdapter +import android.os.Bundle +import android.view.View +import android.widget.MediaController +import androidx.appcompat.app.AppCompatActivity +import com.bumptech.glide.Glide +import devs.org.calculator.databinding.ActivityPreviewBinding +import devs.org.calculator.utils.FileManager +import java.io.File + +class PreviewActivity : AppCompatActivity() { + + companion object { + const val EXTRA_FILE_PATH = "file_path" + const val EXTRA_FILE_TYPE = "file_type" + } + + private lateinit var binding: ActivityPreviewBinding + private var currentPosition: Int = 0 + private lateinit var files: List + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityPreviewBinding.inflate(layoutInflater) + setContentView(binding.root) + + setSupportActionBar(binding.toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.title = "" + + currentPosition = intent.getIntExtra("position", 0) + val filePath = intent.getStringExtra("file_path") ?: return + val file = File(filePath) + files = file.parentFile?.listFiles()?.toList() ?: listOf(file) + + setupImagePreview() + } + + private fun setupImagePreview() { + val adapter = ImagePreviewAdapter(this, files) + binding.viewPager.adapter = adapter + binding.viewPager.currentItem = currentPosition + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/SetupPasswordActivity.kt b/app/src/main/java/devs/org/calculator/activities/SetupPasswordActivity.kt new file mode 100644 index 0000000..aba0899 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/SetupPasswordActivity.kt @@ -0,0 +1,37 @@ +package devs.org.calculator.activities + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import devs.org.calculator.databinding.ActivitySetupPasswordBinding +import devs.org.calculator.utils.PrefsUtil + +class SetupPasswordActivity : AppCompatActivity() { + private lateinit var binding: ActivitySetupPasswordBinding + private lateinit var prefsUtil: PrefsUtil + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivitySetupPasswordBinding.inflate(layoutInflater) + setContentView(binding.root) + prefsUtil = PrefsUtil(this) + + binding.btnSavePassword.setOnClickListener { + val password = binding.etPassword.text.toString() + val confirmPassword = binding.etConfirmPassword.text.toString() + + if (password == confirmPassword && password.isNotEmpty()) { + prefsUtil.savePassword(password) + startActivity(Intent(this, MainActivity::class.java)) + finish() + } else { + binding.etPassword.error = "Passwords don't match" + } + } + + binding.btnResetPassword.setOnClickListener { + // Implement password reset logic + // Could use security questions or email verification + } + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/SplashActivity.kt b/app/src/main/java/devs/org/calculator/activities/SplashActivity.kt new file mode 100644 index 0000000..8cfbf5a --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/SplashActivity.kt @@ -0,0 +1,32 @@ +package devs.org.calculator.activities + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import devs.org.calculator.R + +@SuppressLint("CustomSplashScreen") +class SplashActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContentView(R.layout.activity_splash) + 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 + } + //code starts from here + val handler = Handler(Looper.getMainLooper()) + .postDelayed({ + startActivity(Intent(this, MainActivity::class.java)) + finish() + },2000) + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/activities/VideoGalleryActivity.kt b/app/src/main/java/devs/org/calculator/activities/VideoGalleryActivity.kt new file mode 100644 index 0000000..ed72f2b --- /dev/null +++ b/app/src/main/java/devs/org/calculator/activities/VideoGalleryActivity.kt @@ -0,0 +1,65 @@ +package devs.org.calculator.activities + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import devs.org.calculator.utils.FileManager +import java.io.File + +class VideoGalleryActivity : BaseGalleryActivity() { + override val fileType = FileManager.FileType.VIDEO + private lateinit var pickVideoLauncher: ActivityResultLauncher + private var selectedUri: Uri? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setupFabButton() + + pickVideoLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + selectedUri = uri + try { + val file = fileManager.copyFileToHiddenDir(selectedUri!!, fileType) + if (file != null && file.exists()) { + Toast.makeText(this, "File hidden successfully", Toast.LENGTH_SHORT).show() + 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 { + Toast.makeText(this, "No video selected", Toast.LENGTH_SHORT).show() + } + } + } + } + + private fun setupFabButton() { + binding.fabAdd.setOnClickListener { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { + type = "video/*" + addCategory(Intent.CATEGORY_OPENABLE) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + } + pickVideoLauncher.launch(intent) + } + } + + override fun openPreview(file: File) { + val intent = Intent(this, PreviewActivity::class.java).apply { + putExtra(PreviewActivity.EXTRA_FILE_PATH, file.absolutePath) + putExtra(PreviewActivity.EXTRA_FILE_TYPE, fileType.name) + } + startActivity(intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt b/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt new file mode 100644 index 0000000..b7be16f --- /dev/null +++ b/app/src/main/java/devs/org/calculator/adapters/FileAdapter.kt @@ -0,0 +1,73 @@ +package devs.org.calculator.adapters + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import devs.org.calculator.R +import devs.org.calculator.utils.FileManager +import java.io.File + +class FileAdapter(private val fileType: FileManager.FileType) : + ListAdapter(FileDiffCallback()) { + + private val selectedItems = mutableSetOf() + private var isSelectionMode = false + + inner class FileViewHolder(view: View) : RecyclerView.ViewHolder(view) { + private val imageView: ImageView = view.findViewById(R.id.imageView) + + fun bind(file: File) { + when (fileType) { + FileManager.FileType.IMAGE -> { + Glide.with(imageView) + .load(file) + .centerCrop() + .into(imageView) + } + FileManager.FileType.VIDEO -> { + Glide.with(imageView) + .asBitmap() + .load(file) + .centerCrop() + .into(imageView) + } + else -> { + val resourceId = when (fileType) { + FileManager.FileType.AUDIO -> R.drawable.ic_audio + FileManager.FileType.DOCUMENT -> R.drawable.ic_document + else -> R.drawable.ic_file + } + imageView.setImageResource(resourceId) + } + } + itemView.setOnClickListener { } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FileViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_file, parent, false) + return FileViewHolder(view) + } + + override fun onBindViewHolder(holder: FileViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + class FileDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: File, newItem: File): Boolean { + // Compare based on file path or another unique identifier + return oldItem.path == newItem.path + } + + override fun areContentsTheSame(oldItem: File, newItem: File): Boolean { + // Compare the content of files if needed + return oldItem == newItem + } + } +} diff --git a/app/src/main/java/devs/org/calculator/adapters/ImagePreviewAdapter.kt b/app/src/main/java/devs/org/calculator/adapters/ImagePreviewAdapter.kt new file mode 100644 index 0000000..9017324 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/adapters/ImagePreviewAdapter.kt @@ -0,0 +1,36 @@ +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.viewpager.widget.PagerAdapter +import com.bumptech.glide.Glide +import com.github.chrisbanes.photoview.PhotoView +import java.io.File + +class ImagePreviewAdapter( + private val context: Context, + private val images: List +) : PagerAdapter() { + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val photoView = PhotoView(context) + photoView.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + + Glide.with(context) + .load(images[position]) + .into(photoView) + + container.addView(photoView) + return photoView + } + + override fun destroyItem(container: ViewGroup, position: Int, obj: Any) { + container.removeView(obj as View) + } + + override fun getCount(): Int = images.size + + override fun isViewFromObject(view: View, obj: Any): Boolean = view === obj +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/utils/FileManager.kt b/app/src/main/java/devs/org/calculator/utils/FileManager.kt new file mode 100644 index 0000000..7266681 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/utils/FileManager.kt @@ -0,0 +1,195 @@ +package devs.org.calculator.utils + +import android.app.RecoverableSecurityException +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.provider.DocumentsContract +import android.provider.MediaStore +import android.webkit.MimeTypeMap +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.IntentSenderRequest +import androidx.documentfile.provider.DocumentFile +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File + +class FileManager(private val context: Context, private val lifecycleOwner: LifecycleOwner) { + private lateinit var intentSenderLauncher: ActivityResultLauncher + + companion object { + const val HIDDEN_DIR = ".CalculatorHide" + const val IMAGES_DIR = "images" + const val VIDEOS_DIR = "videos" + const val AUDIO_DIR = "audio" + const val DOCS_DIR = "documents" + } + + fun getHiddenDirectory(): File { + val dir = File(Environment.getExternalStorageDirectory(), HIDDEN_DIR) + if (!dir.exists()) { + dir.mkdirs() + // Create .nomedia file to hide from media scanners + File(dir, ".nomedia").createNewFile() + } + return dir + } + + + + fun getFilesInHiddenDir(type: FileType): List { + val hiddenDir = getHiddenDirectory() + val typeDir = File(hiddenDir, type.dirName) + return if (typeDir.exists()) { + typeDir.listFiles()?.filterNotNull()?.filter { it.name != ".nomedia" } ?: emptyList() + } else { + emptyList() + } + } + + fun hideFile(uri: Uri, type: FileType): File { + val inputStream = context.contentResolver.openInputStream(uri) + val targetDir = File(getHiddenDirectory(), type.dirName) + targetDir.mkdirs() + + val fileName = "${System.currentTimeMillis()}_${uri.lastPathSegment}" + val targetFile = File(targetDir, fileName) + + inputStream?.use { input -> + targetFile.outputStream().use { output -> + input.copyTo(output) + } + } + + return targetFile + } + + fun copyFileToHiddenDir(uri: Uri, type: FileType): File? { + return try { + val contentResolver = context.contentResolver + + // Get the target directory + val targetDir = File(Environment.getExternalStorageDirectory(), "$HIDDEN_DIR/${type.dirName}") + targetDir.mkdirs() + File(targetDir, ".nomedia").createNewFile() + + // 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 + } + } + + private suspend fun deletePhotoFromExternalStorage(photoUri: Uri) { + withContext(Dispatchers.IO) { + try { + // First try to delete using DocumentFile + val documentFile = DocumentFile.fromSingleUri(context, photoUri) + if (documentFile?.exists() == true && documentFile.canWrite()) { + val deleted = documentFile.delete() + withContext(Dispatchers.Main) { + if (deleted) { + Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(context, "Failed to delete file", Toast.LENGTH_SHORT).show() + } + } + return@withContext + } + + // If DocumentFile approach fails, try content resolver + try { + context.contentResolver.delete(photoUri, null, null) + withContext(Dispatchers.Main) { + Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show() + } + } catch (e: SecurityException) { + // Handle security exception for Android 10 and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + val intentSender = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + MediaStore.createDeleteRequest(context.contentResolver, listOf(photoUri)).intentSender + } + else -> { + val recoverableSecurityException = e as? RecoverableSecurityException + recoverableSecurityException?.userAction?.actionIntent?.intentSender + } + } + intentSender?.let { sender -> + intentSenderLauncher.launch( + IntentSenderRequest.Builder(sender).build() + ) + } + } + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + Toast.makeText( + context, + "Error deleting file: ${e.message}", + Toast.LENGTH_LONG + ).show() + } + } + } + } + + private fun deleteOriginalFile(uri: Uri) { + try { + val contentResolver = context.contentResolver + when { + DocumentsContract.isDocumentUri(context, uri) -> { + DocumentsContract.deleteDocument(contentResolver, uri) + } + isMediaStoreUri(uri) -> { + contentResolver.delete(uri, null, null) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun isMediaStoreUri(uri: Uri): Boolean { + return uri.authority?.startsWith("com.android.providers.media") == true + } + + enum class FileType(val dirName: String) { + IMAGE(IMAGES_DIR), + VIDEO(VIDEOS_DIR), + AUDIO(AUDIO_DIR), + DOCUMENT(DOCS_DIR) + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/utils/PrefsUtil.kt b/app/src/main/java/devs/org/calculator/utils/PrefsUtil.kt new file mode 100644 index 0000000..9dd00b2 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/utils/PrefsUtil.kt @@ -0,0 +1,46 @@ +package devs.org.calculator.utils + +import android.content.Context +import android.content.SharedPreferences +import java.security.MessageDigest + +class PrefsUtil(context: Context) { + private val prefs: SharedPreferences = context.getSharedPreferences("Calculator", Context.MODE_PRIVATE) + + fun hasPassword(): Boolean { + return prefs.getString("password", "")?.isNotEmpty() ?: false + } + + fun savePassword(password: String) { + val hashedPassword = hashPassword(password) + prefs.edit() + .putString("password", hashedPassword) + .apply() + } + + fun validatePassword(input: String): Boolean { + val stored = prefs.getString("password", "") ?: "" + return stored == hashPassword(input) + } + + fun saveSecurityQA(question: String, answer: String) { + prefs.edit() + .putString("security_question", question) + .putString("security_answer", hashPassword(answer)) + .apply() + } + + fun validateSecurityAnswer(answer: String): Boolean { + val stored = prefs.getString("security_answer", "") ?: "" + return stored == hashPassword(answer) + } + + fun getSecurityQuestion(): String? { + return prefs.getString("security_question", null) + } + + private fun hashPassword(password: String): String { + val bytes = MessageDigest.getInstance("SHA-256").digest(password.toByteArray()) + return bytes.joinToString("") { "%02x".format(it) } + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/utils/SecurityUtils.kt b/app/src/main/java/devs/org/calculator/utils/SecurityUtils.kt new file mode 100644 index 0000000..305cbb7 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/utils/SecurityUtils.kt @@ -0,0 +1,64 @@ +package devs.org.calculator.utils + +import android.content.Context +import android.net.Uri +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import javax.crypto.Cipher +import javax.crypto.SecretKey +import javax.crypto.spec.SecretKeySpec + +class SecurityUtils { + companion object { + private const val ALGORITHM = "AES" + private const val HIDDEN_FOLDER = "Calculator_Data" + + fun validatePassword(input: String, storedHash: String): Boolean { + return input.hashCode().toString() == storedHash + } + + fun encryptFile(context: Context, sourceUri: Uri, password: String): File { + val inputStream = context.contentResolver.openInputStream(sourceUri) + val secretKey = generateKey(password) + val cipher = Cipher.getInstance(ALGORITHM) + cipher.init(Cipher.ENCRYPT_MODE, secretKey) + + val hiddenDir = File(context.getExternalFilesDir(null), HIDDEN_FOLDER) + if (!hiddenDir.exists()) hiddenDir.mkdirs() + + val encryptedFile = File(hiddenDir, "${System.currentTimeMillis()}_encrypted") + val outputStream = FileOutputStream(encryptedFile) + + inputStream?.use { input -> + val buffer = ByteArray(1024) + var read: Int + while (input.read(buffer).also { read = it } != -1) { + val encrypted = cipher.update(buffer, 0, read) + outputStream.write(encrypted) + } + val finalBlock = cipher.doFinal() + outputStream.write(finalBlock) + } + outputStream.close() + return encryptedFile + } + + fun decryptFile(file: File, password: String): ByteArray { + val secretKey = generateKey(password) + val cipher = Cipher.getInstance(ALGORITHM) + cipher.init(Cipher.DECRYPT_MODE, secretKey) + + val inputStream = FileInputStream(file) + val bytes = inputStream.readBytes() + inputStream.close() + + return cipher.doFinal(bytes) + } + + private fun generateKey(password: String): SecretKey { + val keyBytes = password.toByteArray().copyOf(16) + return SecretKeySpec(keyBytes, ALGORITHM) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/utils/StoragePermissionUtil.kt b/app/src/main/java/devs/org/calculator/utils/StoragePermissionUtil.kt new file mode 100644 index 0000000..8c97d2a --- /dev/null +++ b/app/src/main/java/devs/org/calculator/utils/StoragePermissionUtil.kt @@ -0,0 +1,68 @@ +package devs.org.calculator.utils + +import android.Manifest +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.provider.Settings +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.core.content.PermissionChecker + +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) { + onPermissionGranted = onGranted + + when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + if (Environment.isExternalStorageManager()) { + onGranted() + } else { + val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply { + data = Uri.parse("package:${activity.packageName}") + } + activity.startActivity(intent) + } + } + else -> { + val permissions = arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + requestPermissionLauncher.launch(permissions) + } + } + } + + fun hasStoragePermission(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + Environment.isExternalStorageManager() + } else { + val readPermission = ContextCompat.checkSelfPermission( + activity, + Manifest.permission.READ_EXTERNAL_STORAGE + ) + val writePermission = ContextCompat.checkSelfPermission( + activity, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + readPermission == PermissionChecker.PERMISSION_GRANTED && + writePermission == PermissionChecker.PERMISSION_GRANTED + } + } +} \ No newline at end of file diff --git a/app/src/main/java/devs/org/calculator/views/SquareImageView.kt b/app/src/main/java/devs/org/calculator/views/SquareImageView.kt new file mode 100644 index 0000000..d1e6c24 --- /dev/null +++ b/app/src/main/java/devs/org/calculator/views/SquareImageView.kt @@ -0,0 +1,16 @@ +package devs.org.calculator.views + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatImageView + +class SquareImageView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : AppCompatImageView(context, attrs, defStyleAttr) { + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, widthMeasureSpec) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_audio.xml b/app/src/main/res/drawable/ic_audio.xml new file mode 100644 index 0000000..47bd994 --- /dev/null +++ b/app/src/main/res/drawable/ic_audio.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_document.xml b/app/src/main/res/drawable/ic_document.xml new file mode 100644 index 0000000..91c794b --- /dev/null +++ b/app/src/main/res/drawable/ic_document.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_file.xml b/app/src/main/res/drawable/ic_file.xml new file mode 100644 index 0000000..811d503 --- /dev/null +++ b/app/src/main/res/drawable/ic_file.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_image.xml b/app/src/main/res/drawable/ic_image.xml new file mode 100644 index 0000000..bd827d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_image.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_audio_gallery.xml b/app/src/main/res/layout/activity_audio_gallery.xml new file mode 100644 index 0000000..27e8f96 --- /dev/null +++ b/app/src/main/res/layout/activity_audio_gallery.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_documents.xml b/app/src/main/res/layout/activity_documents.xml new file mode 100644 index 0000000..0c349c9 --- /dev/null +++ b/app/src/main/res/layout/activity_documents.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_gallery.xml b/app/src/main/res/layout/activity_gallery.xml new file mode 100644 index 0000000..d34ccb4 --- /dev/null +++ b/app/src/main/res/layout/activity_gallery.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_gallery_base.xml b/app/src/main/res/layout/activity_gallery_base.xml new file mode 100644 index 0000000..e8f010e --- /dev/null +++ b/app/src/main/res/layout/activity_gallery_base.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_hidden_vault.xml b/app/src/main/res/layout/activity_hidden_vault.xml new file mode 100644 index 0000000..37b84a4 --- /dev/null +++ b/app/src/main/res/layout/activity_hidden_vault.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_image_gallery.xml b/app/src/main/res/layout/activity_image_gallery.xml new file mode 100644 index 0000000..2eeda20 --- /dev/null +++ b/app/src/main/res/layout/activity_image_gallery.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..acecba5 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_preview.xml b/app/src/main/res/layout/activity_preview.xml new file mode 100644 index 0000000..b3b88ad --- /dev/null +++ b/app/src/main/res/layout/activity_preview.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_setup_password.xml b/app/src/main/res/layout/activity_setup_password.xml new file mode 100644 index 0000000..b70ae1e --- /dev/null +++ b/app/src/main/res/layout/activity_setup_password.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml new file mode 100644 index 0000000..94f8c72 --- /dev/null +++ b/app/src/main/res/layout/activity_splash.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_video_gallery.xml b/app/src/main/res/layout/activity_video_gallery.xml new file mode 100644 index 0000000..8514256 --- /dev/null +++ b/app/src/main/res/layout/activity_video_gallery.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_file.xml b/app/src/main/res/layout/item_file.xml new file mode 100644 index 0000000..831e46a --- /dev/null +++ b/app/src/main/res/layout/item_file.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..4ae7d12 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..4ae7d12 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..f971491273c1df585ec99e8c8cdc7b1106417a3e GIT binary patch literal 1518 zcmV|K4<@hFGEE1e*%iV z%@VcCM77!^Dh#MjhWud53@~2owNTKukz@Xl@9y`&ptfxriMfCONv{lCA!^%325^e1 zdmVpd2c`cLfKLWM^A7_+l1`FJ03-=gyl{YnZkJl2sC5s3m30?jgppY+s3wM zod>^dJGRwZwUa6%6)W3Tm(I3Rp|fq<#`C_<8F`+2&&3m!bZcu{wnh8g@Anfy12jV| z#P04Ik$D9);?u*#6S~X$K#n9yk>t_6aD4Y7{WUsqmI`id+p3j$F78efPUsN-L1cx{ z3I))ByIV%)&;+5|<30zDBsI>gn+%Ij3l2|!0ROv92_C8%L_G8lWmx)9f((W+NMS(+ z{JtwpqtL{XA+icelHh}VuHhh}%&)qcy{cmdDDsyj*j@d6bYFzbL&=^28R)jx$aG6F zNS!gm|9e9oN|2SX#6wl!k6-reUkKHM2#Siymrw6GV8?|#6eCT7flQ-9xiu*d1uz9M z`hQv#14$uZpB9Kf*fhHsDvF=(cXzK z0SsNdjYo!sxbobx2w*7tE`FY2>9ffj!*XdNV-U6QG>$BrBvN$QJUQaktDlRr+yldY zulNi(U`WshEgQW0a{l3&perhBd3o6C^|)k4iwvYBil^qF4M7zEfLb(O-S{r-r>t;e z2DE6=N#Mbd*4&6dqKIFl3c;Tu1(>=%t~t=_g8*NY!(LHKr%e~Xz=cR0*aQGS7b(Gb z_`JLju7f}0)c~EgmvK0~1i^t6m2$|+D`#`a&TlfpOnLllZakYgVrzrNKGN%%__R#H z&N4YVt+y}r(8E9^W>wjJWpR;GN-2BD;sR_rfWu#NcbO~ao%^?3{M8szn*|d^q1aB2 z-6_$cMuAvICV+vB6jd@VKyb*u+;KMZSK6XcNgK)ZmY{ji0H8%Fi=Y6CqRd*UBmo8@ znN{-4S@v7;4&rZETJAZQBUg%&3_-+el3aBzSD(uy@tp1{PoBwkD}r=VvY9d;z_VIb ztw;eu9r<6rEE8qE7!X81G1)S#=B`BiU0`7Nn~;zw-i&V%p_xV_zlKF8f*=^?6b)}` zeDV!`EfM-7il`AN_v=jokxE>A{Vt_ZM~qh)To{;sd+4nF21o741ob%m9C&Jys zO4I`bF~~#)z=B|47>6}bCdJ^8I^?`_%S`y%Mhrk8>=~HhL*$%D5FJFoD}x1*6BYmv zUGmwCqo4fJ=vQ$jtc#PkVT5o_x)cBg;++}0Jo#o#+iDnX7$+es&YNfWdbr$$4o=MW zwrrR%@gcIE9uF4wA+*nBzMBPjiFLCCVBm;s7Zh+F7z^Mz3d4}^p6i%xG}8VHAiQ`D z0*I{fszJyQQwEN)07SNUO$d9UFM;s)Kq%wm)q;VB?a0juz*2@(5YYf4+N;~EAt;WC zkjC{X5l33QI!{~B#xFnm3F+PDMj@dghyehjHw1&zt0>~P#XBF}f@eMm`)`DuU))dM zyT109)kv8_!*m2#5bQ+6D+erGM@5XNf7d)5`2AxS%5B~&%+a?z1ip@Z`B*yp@>*WL zH8=%D*j_>ZRs-=$Sh&*^zu?_9kGJhs;Qcfr5E{4rq3%&Sq4%;ohsyeE`ljsa$0HZJ z=%j-Lg9ea+P{v3l!5|wzLpBsLO4+1e4}HJ6*7MP) zZU^x4@MSfj=EsO_((nwe&;qsj|I30Be&KcVO+Tf&Atj09M5!iE UPw~?UAMh8o9S8vOXW;*n0pW7d5dZ)H literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..e04a0c5d225700c9e2a9174ee71faef23a8a941c GIT binary patch literal 1136 zcmV-$1dsbtNk&F!1ONb6MM6+kP&iCn1ONapp+G1Q3AAn71_eF#|CcNDf{6Z4fD>;2 zxZg-55{X12kw_#GiA3UUJHqXT7C=Jy|6Ysee|iHXNs{9>`TtLQ5d}gdQ1Wt-BipuW zD`Vo4@!Lt}PDJF;OfuJd7sIw~BhhW|_TRUUk~x$0t6WN$153ref8W{8x1rUnG#@kHxWOSPrSR% znQ(jG!%vv-4}$w@v<7K6N}6Jdx*^Q>F*m(BgE+l{xN-yc2V*X48Rk z$Z=$&!@t!sG)GI24@r)EYpIvQv$^Cyk|D~GBoXmw#hjA>KZ@7hJgrN)c6sWCO@o9k@qgjQd{QHZM1h|C{>;j zg_kj+E}-`N;@e91Mj*}D{InG19ex2+LttE^$O!z75I>p>cAYknMGKf=lqCjnNB=yK zW^~cg%Djn}z#2&e7J5cs1~Wt-O_cDchSXuakN$aYnP==zGv>7!8G)FmiPGcR_yP3K z#R6j?u{W*nfD+@ekT?~TktvLdPJ(gsCTjc-LTpVVF4~Jm8ckFk6UIcaZAar0U}S?m zkGAiN0Dx)QtOyZzVJ)NO-l@Loq4OH;@_Jy=7jYA9y8a7{4bfBPz5V-q)}sLg()t2p zwLq*x%Uz_BCYGYzG8TFvgY6a=_X;vZMFz{fH(>f}Z!m+26=~<|6nHQh`;3KN8YH#n zuu7T{Q|8SHGIp%V#no>v5lA!oS}ImVT?R7U-gogdg7$() zdFH|o{Iblxxy8v#hQAgV{7#;SdwE#W~HYbqXMFT*#D`UbZ0RY^SYuW>7 z#QfUOHb3MY1h}-CP_R*%ce#8NI5fl2oh?K1_GR9*A=!Ur@MJy-67a8xW`Ilnxr|T3 zs45^Y@L?4itV9E+j}9*pVd(yyYn-2zF5)H{EJOqRAm>h(aOOUE=eToZ1Z^~QO`j&F<7-{orsp7_@Z~m>B5EYFmM1C C1uYZ+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..2659bb8e660167bfa04d388ed8830f83ecf66f7a GIT binary patch literal 600 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 YAC>hAm>+q`J@iZO(Ep$S01%FC+eTpf z+cAJ`rKbh3qx5t@0|3W^Bxu_VNqTc_+xDJp+ups|*2%VQ+uob4lWp5^41$GS0IY0)KI?O@IYZsG0w$HpK4D3lQfVjjX zr94SYe4=pF95grY1PH(z<)%^}6aXP{TvQ~P6h~K##3l+Gl;s(#?p}=wisfQKn0|M3 zD%`*Tu}P#1>kRtw==1Hd^ll!Ag^gaDv;jbJ-rN#Ew0PtITS969q$kZPX#l{`aIv03 zEV?`TerMpEXwmy>hTlxGAqL0HS_c5M0A^+YKq1(D@5&7X0)`Q%qfGICm81iuk0iww zfI;6rJ_sO8X1AR2*mn2Izygw!tU$mJ5H5;{O<`H+av{(EG4Vaq*J*q<%8}$H01y%x z2~d`ml>i8gCxQbS_K7K>b7joK{F-GXjNW45FlwA6h95&N&03@)Z7bt8Nx2JPX3xxT zE9pq=jWAxFfMCR7S~Cbk5(NNq9$*eh(qgqzwdh zFa#+AA$H}XcucIMg&&GB!;e&^1WA%$Fb+v(QjS>pNzxPuOBth*M2SDj;ayKm?Dt41 z6dnY?!$@h10f18k{oEli6bNH9hCmhp2pk9mfS?eG5WsPF=WA0kin5$t32)E`Eq;P17beyam)8;_oMjDShVf`&7zrdo zYNHa%Y8d$(S}RyNh)}{LN-%~9h7d`jOcGntg~LmaNs?d)p5zrV-s>n*!c+q+_N|-yXB)?$r;(rlGdjo; me1QfKG(fw-3etNuT&(jF2HaDo{8*pWa22><|o9vtKV literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..31ba93e3bb6792a5e337b43b16fe1fbb47529cd8 GIT binary patch literal 1078 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 Q+x>g>$`NYwEA)mj0f`qs&j0`b literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..34faa0a9e02e37802a9df7daa0548c9ce54f1e41 GIT binary patch literal 2242 zcmV;z2tD^wNk&Gx2mk? z#`dx+*2Hexl{r{ap?LtLiy9G@1n3cxtdXDqwtg21+BR~`AMFEp-THxnaoe_m*!K3H z_aOM;rjaB`ihaycs z&DPcSjVIf-ZJT4e-CY^aGyRWrWgBSOXe=xJ#VeX&%-FIi+u9~(IV)FvDqb6f5re-*|I6_5 zKfqtMhx7^F^wdKj{UCjvs<$!jzhj?}lu89c^df-zhaK3*|79BS&~9$(87J3FdE=vR@QQ08&U9)9XE?#RY-v12Q#pLLgD0kVFFm17};86$#lR zH6kxyuaJ8u8HABaDAXV?zue{7E-R55*#4FoBL~$oq+3!LC@__^G2BE(eugEu%u#tVeMS?3~qDn?4fLU88zV1TKS{zgX1R*gCvJ*C;^ zFl4{D6^*4*Nvb*`b+nXND(vUg*%BE`CY9XDC6pnQag~pXI^^cFpqoq)pTEgiq54$h zSu>6}PA35EeMbBuBf04)<_P9;$@30HNv;Bu9PLCt1i|uJZrUO>GB0>qNvdEiGQT+P zQ>BPeo)IETYP3e!ho+WDNXl`H)?C$e(GrP9I-5ue(K5Bt>SaG?B@&X>LEY}q6dg+; zo=zHl=@S!5Aa)+Js$R2@l%Q^c4^5|GrK}j`lJB&%85u{&NM#Vl$#~;tHSo>G*eAO` zz59XKH(QkL?&hnAGcjloZV&EnxOukQ{Hyi_yF9-80Xz}zs5|*mY$LR(ks;_YJ>VuY z{#EO8%99Vn2*eRCl)R$lXL05oA}QS8BDF1&2?F^>QNF&UsRMv8vXzmT5F#(nEAtXJ zHSh)_Rw@Tt&dr*!GeWpwM^_F>+^j&H?o5qTOH}0>IXK8jhYJ>xH#4xs6O5v@3SuY+ zt%-z1;c?f=elhYoPuhVf7{#Va1TPj-3pzU@DbAgnDjyuy<-FCqkt{Jr*A3WqnJ)|X z+oG8mC^FW`G#0)0_UL8)b4X!F6)DmV)`@JJ|K@Mday-%RhFpdegmJVm7L_HPr6w0X z`mzi|#X2qNAVoLs)2wO4A{{x?WkYEgsD;UHjU)GP$cP+!W50vC2HhrRXQ>RV?l8v zio<{&i9!{%;(?=IuGUzvqK>M%vxAbP+X9CIRfNDm4$_GjP^7l1`5q><9%|14h;$%B z^^uzO#rh0*S=(%9nGK-Qd*+!Gx4-hQK~_-G4Gz5Xn_0x_yEc+A7!BT=7-n8Icz=3Kktta>)`MmMMRGjQ`OZT=s?ZuzL~_?J2kZx$A)*-76vLYW2;Q1VEWXdPiMD+PrwIpHo2JsE`3(l9hPzm=0iIHO#ez)B#3qDOz5s zP_Xjcfl8Yy(CA%+(xXjDQ%n3B^YVk|zdS#fefCEu(DlLe_Tk&?$}gPf z!^)RA&<0c>Y~)69-6NwI*WW4)LLzTPR5o4b2-H@+{Ga5!8&lnVrmoZAF~7!W?7F5Q za~vAUTsvR=zu%tnxRaOE+P>hR&3>ZMkmE2CV?=@=GDeM&u{qnas>x=I+GK22j7?!x zY(|7gdpc(7cex7qUjk=-ZA?Bj@xPVJ#agYN|C*&!1N<6U`(w`kNnk|w%TbU>dz|BD z04*>hOQ-Jn;MwLMkVxjL&Ia0-N9UY_HiO6%POuAxFDYt*+PmAo5%>-K1^xpSz`PY8 QwOTB?R25Jv{+(0^0E}xlo&W#< literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..1837ed0801ac1cb197f64f3d971abcb3ac1f31d4 GIT binary patch literal 1998 zcmV;<2Qm0kNk&G-2LJ$9MM6+kP&iDw2LJ#s*T6Lp3CC?4NfNr*zrp06@UbOq0ulY6 z0M_{VlU3}1Ie|bR5O}^O1OkCTAP@)y0)aqaXz#TQ-{+h$3!`n@`2Wk>ZD>e9lK6jf zMD%|GI9GgI$52pk8%dHR>HnW@pei!L<4Ci;*TY+qWZR}~<=oG<{oZdP%D1VXRa<*9 zY}+;r-TnXZ9Lu?_?bxFen^n@=RaPq1S!u0bV5_xt$E?iCwlVfhX?*s#UPzGS#%-2? zWH=UfrLsr>Ip5%rqw({S4;94tLYRwS2&B&&a|V#Te;Ikt>}TQ!Xy>H;EV%!? z_|ow8VhKnncmRqA7_m<@_pr)V55W}1&vRaU|8mLNp%94!bPup%ADQVz7eF7v&w?{c zUn*Gz5(6$NevrInu9mHCgKZ3c@uAX@Fu=e7E6nh>^+WJm0G0^OX<>kZy#)UOSmul8 z4i12eL7yAp*9FsmLP;lsLDd2Osp*Vq1>_7YQ$4_YTDStm3odfaI&A~66PsWK%#2HH zHhgUK1p5To86=s+U6+qG# z{;4q-a0LQeR<_L74vJWUD-cD#zzS?R_s`abp@=oua@c??P(_|V@r5miP5jvcQRD{% z53mhe4!dwe)CuGU=?}#|Y;Bx?AO=5tP{aW|fdcRWiqT6xu$8}Y1Y3c8ffLwat@b#o zh!fb_a0WN|cBlWK9~9yIjWgJCILDtUP&BZ^+6pM5h)cNXKXmf#C+sj@uA!eb9O&Ar z`yTKUrnrHbZ-VK<2x~u35=Gp>4Qpp385Bzx>)Pt8@GvYn6rYU?5Cj~ahWrbcSuq{I z4|w3K!A5@%C7f^bYf`zNKJc;CbZ% zw_?>Pm7rL_8n0*7rPyBcZ3-j#Hid_}&yW+JWUDvH_9orvB;DD0sQ7B+w75c9S7teC z9Exp>(R};*sr#N~gsrc4*tm`q<9xfcvQ~#Rps=GrULcC~j3uwFLa}*0>g=w5)@Wjy zuIj#gteZx{$a`TOQ1@L;tT|Xq)~q_MPFdyb`V>2;P(xdV;t0l&(=?hb-{VBF>O0*Pf@@`ci?wMnk&>%SiAzR)B)F|XE=NqS45(%U3oa7K-zjI}mR z0CjerL-B6L8tvZ7c;xA{hH(pGo|TsCc$V{8*6Of^6!t_eCTjIHj|;e}o8%!W z11l-_a4t-3D5j*eR#I3`x$PcSe(Jt~NeZ)AWF#L@)Fj_~ZV1m^-P2ifel4l~T2f)w zbpzuq{f7;yz{Wcz^7UW2P4bWw8HM_JjA6Sfo8(dg)vMBije)k`Y_)%an%9jG*lBB$ zuT0tkrYK1}#nId(pH%y>tGY>^S+j>-T}|@shY4$vuLDAGci5zx6Z2{SRY zMK{TNtO4g~i0$31wJA=`@3M-)hSTqxP|jmK%>e`PPjHiba9G@7oEmwjw@JRLK%(CA zw_m_`(sg{*Tobp01zi0IX3-pk?!B zsS23EUVv%F4!nmCA^{We0-3?e`D_|AGxER$+k9&!|1OitAZoEzqz~kN!9XSfB^QJe zCIKPj_g+fwCsL!}QUY>23MgrWJhV{KsJpk(QXK{N5$U1xdnykFL3NZoH1!oALL&F; gT^eCVItnf#nV(1`eMl==Etbh#7W1lL8%#idBtIJJu>b%7 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..1ffa6550fed4dfca7fffd7a0253d6c8b954d15e5 GIT binary patch literal 728 zcmV;}0w?`aNk&G{0ssJ4MM6+kP&iD)0ssIn*T6LpwMejSH<27KV5qF;nQ*fIZCZsn zEr&~CR=6S55pVziEF+!Ywr$(CZ5xwq+qP|Ey8p?xZQGv-@YVmT|5yK8IMbo8LTxfU zMRk_q2vCc;$;cM_Ck-Tw1fS#zrvdI^(kA(DCb$$}JFA&5p{R@4C&Z}C%}Mas$r|qs zWf2jizZr4K!Vw^Xdqiy~389wc1Rd1Tvl}(nP@7IT4@yY#Zoma2JE4-fGo5E1P8I%% z-Su2Buo?BXm*p#*4d)`pT@^=sPf3{% zmAZuV`Q9F5fk*H*ooC6PRq)GUsI(-6w}N*vud80#64KkjQRH!eblk)AmT*z!rH7sy z*xnWypT(Z+>~%U8Bo$mrsz{dH>|7>hkV$4q!KeBog{HG;UW==`nJzIROf>%*# zfP|tcRAx^}yvCZZDtJcGe4nKzR2ELi5=0kAzN+BiQpR`*DOI7C6{x&7L9+|rRd6Tb zwkw69vMMw_G`sR!1=oembXn~~#YU#};o{AIC4KiWP3N5!Z-8Jc)A?BZjuB<-7M9!2 z#ejFVU;F3;mCz#-;JNi2osQloOt9i|M(p-mZlitTTP$QP;?bT}hc2UBl5G^X@mCsNgoe&=`-lm|j#K zq56aVydAIMZ2Ry9A6los;xpcoAIB*c#LQbX4M#U%-u)8{5GmU83YXzp@#!ykifXH@ K{$KsS`rnQqXl^I~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..923d32461d32e3041ceedca6f46e2592faf46006 GIT binary patch literal 4440 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..0403594bae3cbe586898570195c6ad4cb0f7e0fb GIT binary patch literal 3792 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%0D#QNA`&7B%AJQZ>t07GAQy5W zMA5uhyi`ZG(}KsxKcB_fSIT2+8m1;$q04|`z5!T-erxpfMYxb=JIVX{MeXi*u{Pec z>bY|~bTi(|S63}7L_d%+6qgbymmqwVN?(=51zZ&OH%^0N;;?!zskXkBX8)e1kM(*= zdD5`F6y-$e1u`I?)vb+=Msik3ONS70dA(Ry353tC_o9!Bdv0U5tj~MVidKC{WJQ+{ zVL}OE$=hWh!9q|y3lLJg-F{Fsj*uH$lZE5rGBo#QJ6* znn3n`AP;4YKo7S6S01pc3lq>{`v7SCMZA|jpt0;#Kr$p{l7Cyvxk9ro6qFbay3aFz74k;>y3Mh(_m=@RNO6RCMeVGm)@$BB=wmx$@J9hlknFMg*V?zy- zTjd0rd1OEVq>lEPD~d>Lat5d@E)Jm9kC=xn0pk6chvyw}H_q5~Y|QG~h`w&f00w1Q zzcgz}QzfHn7eY!Z#Eh(>RC0L{d8zc}(V35P`Qe;7O2-e>d-Sz*cw_6Nu*_PUnIE#p z@yV@n0@?ih{OsIfvP4n^0ubZH#iga5LA4*1^h`?)qd~fT#CuNlPW=&xUumr$bTgv0ZBHd65n?zBV<&6eV%mb+b7=Vv7XnnigUIN0>Y%J~> z#Plqt2O&Mvbfcy4e4#i3d?3BrvB5)TMi!)tl)_3QD|M+fDhplNX>=O1u_Q?t{opxg zXagZ`$8p?lx4rLaw4I(PJuOQEOA0fyHc66Br!#9$k|a@A?AH&2_j6elyArg0hyulK gZLKX4SuQ+Pi#Kf@t);cBgD*-Gv?q15ny$`i3Dz0c4gdfE literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..e6ac4ee3a237a066f21a58757f9892542f8955ab GIT binary patch literal 3644 zcmV-C4#V+MNk&FA4gdgGMM6+kP&iB{4gdfzzrZgL35Sv7w$0!lj*tEu1_UrP5Yhh$ zunW1u6Sx2cR-gx%g$C{<8=OIsi5=2?4*;@NCTT@vX^|wY;A11ql$2Xaz=Coa7mV@M-lB6b0SpTi$3DN}DFuN<{0Hd~%Bzce5B3S+~qteK2BuR=K z&IjqBVxC{z{!ak@urYyqm^71N62}BMN9x><{Q#7eIu*kxOeKcc04NqTpgyGtfCWpT zUy-FSRRK@5(-*G>8UPHkO^-nqJ09Ylo*(J}w58n!VE61&fJwWC>bM8M`n{*bI{=pd zJ+_W^nhVTMsZzpeqVUaCdiBoUmq36Vt>LfV;co z{~))K<_znQg)vD1yOMB(u!XRe z&=Fd}L5O+64}`A>Z&CCV;bqXQ|FqLHXhsk!=-2ZY)!jxqp-7NW^cMjDK~_CeX`2RQSWP$wLN8O12*e^)LW96;2s^Mw z+`a-+e|v+tB!)lFt%P$GA;+Tz0P`8rOuF`*)90=Q5W*Mek}NK1+mAhu&%O&FE_nu) zW!L@T?Bjy}m%d8Em}cCq1cW|5S*qV9Sv9zMNnA2{DoSxlY&rToEp!|*mH0rSER$tA z`lGXtOYr+kIzRZ)G=$W4R}v5=iHHx9z_bjOS69`WpJ;yUTTZLBz!As%%>)u+gt`Sytb5&gJJMd8WFNSAxkN~-XT8=6tOa5ODGgah zt9Gl;^>t^BL}p>2idh z5vGHLXr+E5CHTNX8Ytq0AtG%;_^2bz#|-#u_?WPc8J4gG;UmTerV+~tl^=0`Pp4CZ zZ3X}Y?4PWLXhFgco^$jEa^iUpIE5LZXAAoFkdi?Yj1bUHCIC9-h2vap%%3EJ@8kP&X++(13u@cL830?%w}XxZZG_V-WuiK( z$q3PqNhw8D)FYVyG0d0@K<%KJOcgYw#YlmItt43T$PTIrEzle_l!<}?!3Yb)OpqT^ ztkSegzn)kiV8H@P)Hi~Hl!2%RI-Lrb?QTIm*lC}@1AY?Ry~l==KR+lKz$@pnj#zM5 zUS8FGYD>T$(N0v)K+Vl$i)k=T1`1^0qYhk7ejC(or{Ux#u;3c`Zz!(w4nV62sjAI4 zUo3AeP<0H+V!->SB*+37fV#m(qYWimJ?v?dsSp+f>@X8!C{`CB=nbxDn#X5OYLBN6 zStc49tX{Zy*Qi_6Z8HgIyeRGSPDq?@fOgNraJRZ|v~|?ta*z_k z`!C|7Nh35I`wEnj z5pD=SZxg?`cZR&>Ku&6p`)6iz2KF0deHfToT$}u*J-*Z)WB+zJ^cvuE7l9Mk1K zkkW#Kp1#z=Tm^pL<{Ry?2aLU=d^!yq4!@*rSj!0b8Txi}==D~R!4$)jU4J5g# z=}C(O882EU{s<)@nJB}(HzP)P*zoNlj}bC*)M7l%J5j>D_~SR0jN~&lb{5597NG^| zxrPx2$E{#buH~4KnYEASBNgIDc4P^yIc9`T&NuJJjI1!HZ#ZHdsbsj2EzKN7vc1=! zN|_nLI53q^d$7$G2EqeC9jf`QCw%QGhGi;|TDt>+Iwvx@!P;ME|2Tg68efYg-7!zR ze()2o9gn|$e2at{x19Ky6F+4fzq>pBOIE|alGk5M2`f~0t-9wR(RwP4Eb9C9(H~gL z>>u&i5t}Ckdk_r+3r7TCq(7#ojOB3KAj-!FnqoxvOBRb8c z|9LhhJMvzXh|G@4ag8DIs5?%Vb|LI4H=YE*E+33TulXWfs{os)c$Ai+&D{SN;eCcPt`#X6btbX?12g4l0fd*dN$#0Tgk^@&AWsib~ zQH!NW$cd8m4FatJm%yw4aRubS+xO>Av*I488|DvR-%oNv-fRdRkR}HPB*!|#XZ*q7 z5le@Hi#=BR9DfzEb)GHuti$GUfHQLg=k8^|nhKi$Ra}d#7f$Rj-WR%L%b?2*^SB1v zbZMS%)DDvE>L?BBi~KGdFF+4e6vbrWs*l5CA=`epPYnfL@3R3`!a|Iw$_lx@2YFw2 z^dtw4T#Qq+VY>{iWDD6q7X(z<1+Jg*yH?PhlaD5S#OP#WU!^X%fcrFf#$@D+bWL?O zcpc#4QokO}B@A^7p%c0mw}U9+e517+bN-Gr#$erNJf94sF);59jt;aD*>UnmQ=Twz z2!LJJeN-qOdA6_-7|PFLz6*KR9hVyA9J{>~kLGc~W7wz~j&ce~KsUT*H-ouw9qINs zs4BHci)FZv55Fge0TIE9MliPR*>ap6iUDdN0iJ&#_f7)6a+T>JxPA|C-b zJ@>>?foO~eHIL|`tS%zPfec+I3?qw{i!xSN48TB20JeD)=DJ#OY6e*QNYNg&nkxCu zSx#pZcHLAOsK1Q)mbPim?j&#}8QEX{pyIUB}Q;t)OL4`n1 zW$A6aaKDg4+>8`nzYN-UD*SJ#&z6nzH4IS+V-b7x;eH`f25B0kicSACAGrLJMrg;^ z|6d3AML?8(%tkT@wz}U>2|p8D{zvoiSHFMzTgB7w`@YM*D?+bh7{jE9pd(wNpWjz~ zS^aU5N(c`Ek6o%>|F4XV_I4>G*t-e&Msdz%@PsMYD3`L22>tc{$*24>c{$2ea|M2< z7kZE(Ni+}6@ZGD+#o(z|gAf5CG)n2>$f?l_ST-T~s1X{D{%Wl5cKdqcJiXZwfl-3D zS={?zFutRai0TqK%f0iA9rx3OcI<=^m5+SkT=i;2B23?@?!FX;Dun7U7%563<-W=( z=1<)B5c;biU;NKh!AtebUxxL;Bkx_W{VDh8IWVk3qSm4HTKc>;oD??DjyA{Xu@`Lj z%=!^$H+nxL1R)b2qdkY;nINJEuw zyb@vd%-ESDbaE~C&K0(D4VE@omZ@1m0SUlR4+_kR4$UJPR8b6r7K0$Y0@lUbEtl08wmxJv{o2O$neArX?sGsCanr*DM)PiVdTtGmO-;$OuX z3Gh`(AS@uv+tqx{NTGbi6``es;-{)wn}YbWG4$Q^KjDAH8U6@>Fq=*ZWzw$7a^+?t zwFZ$(EsY2bm0PWsT0c$OirP&BVImBKey8FOuihq%HglJa-NzV!>qo+!1sQLiB$EIJ%(} z#cd-gN&jUZGrS^V0$8bkBMk_1h#k>vCC-J987`~p~# zUL?WYC?6=8OxmWq=3j9H1V#Rj7PM&Fidsv}Dy4A0oI{8rY;QH6fZ0KhO9&eG(KfU} zV@C-DlqLu;tFj{s11oG&EsCkh83_vT2z7Y;z*of@zi=zPLkTKbmm)>LAB;sS(+X-@ zfodfgBuHqGxvY%Bs53EEKGtJa@Q3mMKE4(5_~|#uJQM6E*{CDZ5DpE%EDH+U>YwhT z@r>3n*uRhdQVVhveirL+CTi2Hv&d|=@&^Q%Yk`2*+2}L9Gv6h@Fdx$K_)!GE*ws_zmZO- z0|gKZDMbtMK)|kLc!3dt5COuW+Z1fWD7gLJH9-SsKqOS9^%@jlD@w2kAQ=-ubb?>o z@V`bwwSpNGeyDL%!#1pWgl~pLg0bdt1KfarV7X4>00JZO$hEqpwwGXX(od+7;YUC0 zoXu&Ramn5Y0U$JjsQcg*R|7|awXaG9$l&~RU%ZR24>Ruv^#&k3!h7yJ;2O?2w1)rz zlGR;T*=zX{c{kvQ5Mb@^=3N4#Rsa$qQY(U?#CnIxnjwN54sTxpJe+(eG2)g}0PY*U zEPTr#iN5Q1`U^NjCb%ep8kGmz2j{nxuHb)^fGSH_e13WGvEQ1m$ zl-^3`Dg=$y+Kd!SOY(q^`)DmQRHR6AingI~FIKQLi`LGYzQzijei^)AiWSE5x1j_g zcdSr8b`XdfV+Cj+fuP0;Mhj$u0I@=O*+GC{A%GJg!=-;dXR~hsbvnAaah{n1A#3% zkLCp7rSlc*I)Vy1gvfGWtMW_Nf$tU17&uu8=x!2i;B3i&-x1dMihCGZ$Kixd;Pp9B zc=Kf4-TxkcuPGZ-%VubL=~>0g?@{N>xGw;Yu)}`;R&ezkt^+PUrf;! zXs(uVG~J6u6ZPDg{!)yr1Q?Nwqr}slIxX{-fpvi%bP=}j(HZb`pKdW zNq@kOOlQzV*kaxiYI;uy@)eW!+?nhjIGI}h49AG*gU=pAldo8MexRwKz0iR9BW&s` ze)3x)#8(^#^vvK-0}b zr!mb-LHe;y$^b&%Iw_zCNBHP024yQ2C-h$f4d{-rwXc{YnFk6+HaT!r%?E7cgDa`>|j0w0t%r#*)&(Ozz!v=+|VMmoy^0sAFQvoiC{hiii71! zz}QK3AmUER#kY^N*?VQdVgNJqobDR|>V)u-T(CiF*S3@;#nRjA8 z1BztV`$L4{8x4RPzv5*MKsS5uJFP;&5Xf`m2hP;8Cn+aah0buScUXK#O_d=cFIs@HLmLG`n)fNCa@f8c#k^Ml1Ot=mJ^khp0i`o0! z(+f@q3Y^GUm z;(KylVNdWou?x}aEADXOD;6&5D@I0!=8kYnU-7+at|jxpg4sKF=X<>cuj|ODFnhZr z(o*{P!P4x#=jIyJw1S2Og{-ZdT+_GO2v-?Xc?uMCh9hdQyxJxbFVHXqx&*>~Wz%5G zgbk=u20%~#1cL*mDmuMv3wl@EWyA|K41p}bH+!cFOL1#$Yk^X%Z zz|7t!A9xXjOUh*b0JzzEK}1TU$o`B0BD43|g(uQeA~mg`9gA}MxzQEyIybFPeoOTD zipxa+VW4aB1=&};5ra@?015#F*(Y_$FuB@JcdfFU_hb*yn!R`Y|Ln(-uQ(9~hCqS? z%+2134Kcdz*#Hoky^p=$d;H}R2$%E~d#LpacyN1tfW=q5d5=F4h_1Gq zQCR^OUolCtnh?O5bE|lB+dG{Ez%+Yr@g=ns*oQ#T9l29eS9R^~vhL8v3Oy2$E6pix zYB|zq^K7)C!0es<|Jm=7Q-9Sr?x+V8e+9hJO{*I&e8uG=AT-d$)mIDvocM}`KQEbZ zxQqg`cP=cLy{~wnaBmp{ok6HcrX;Fo?+DNx+E}4GA{slX4n*83xdfZe9r}WZ6x}4H zdzY&w4q@-k;}?T4PyBDxPd|19>a|<}F`3@Es}le#qOg^8!YJ1D$5cy6ND2cRns!3ovW%v`aWP2#-PY>_p?pm#P`d5>$6 z34;@|GmY%7ll#7Xn2XUDpK6Shz1G>1|Q>VsE@)$^>up7Y$eP z>JOZOE}%5enTekz>HP-7WnBUBnBGwVx;gIY{lW5$KI4Bta>dS9LK`*RCwxCZ5Fb!K zi#x;cfMR2vn)Y1)eb-=``&@Biqaj2$)t6$vflYP;N+5QI(6?%>7Gxp&caq%0zxu;a z25(~%eJZ>JtfdTOz}W!3+9Jxqidq@$F9*))4SNrPY_iX!*6=2a)!z9Hdk+BgrcsVG zHK6dW;l>}Cy}5K58|;DTdMW(DgaWwcY-c#B(a;%P9HBZOF79nv4jK=}H{U(JDR(op zyjlC{Nt}33$tBoy?$8%Rr0DKW)z#a@jtC5=y?gvy1qE;Y6^U0+=Qiwpw7~GXIEZK$ z#qa+H?sjs{Uzlg$qJz@4u#0qr+JN}iE8Q~Hbebz5U~_Ilr=kJ36^9~(c;qr4rD>OL zlH-~-Ba$|P{){!Ajx(YTrEBRtL3tu}1~>`th*e7ZQlbjqS{@$?fDZUCa9ioL9`UN? z2;hl+%r~V=p?jPgKtzcD1a1Y;OMb!^@G9MAOY3o2>8>XlagQU{?#?)2g9xn)zK-CI z9SI`fFz(ra)(JLwfpj3~gl`}r?c3r`@TwZxbJ-Dh>v0)OO*k4Y`o8!|4HVdbVC-r= zCG0%t-PEAth=Y2Rd)6>kT<6kxbVuWw0v+h*odQ-K2dwMr_kXgHYnT2&`m@|layrB0 zb)$Li58_3CEjEA-asv^p_4gU_iM;CL6-w7?3$tmma7CBc9O_CydqQ_<7fRxMwy=G^ zhXR{e?GwI?YhT+2B9iUNDkS`mJ9+rfL+)OJi80DI12{chnbI5eNp z>KhYZM&296cqTOPW+?_Z1;h$kOBJ3Z|q*b!zh%l(Rb7%0C3;)-Uf6><|^yMzI>}> zFS~B!(10J(HLb`?hrPveQ0{8M%**BET01FApzb0AI%tk_%KNoDy_7{`s@Zxg7)iQu z`h^pZ*-7c7*K#b`s5&wwheka0^3&QR@Qbk0OG$=wT`JS_{6H%o84YTmd(NdJOuRYV zogotOo4jD(ZMIsfZI@T#iDEn*Az$DE@_-MtHng3$4FzNe1v0^1rL+H! z7r1{V);A&C{w@o5VPkyvYD1$IQj1J#v6gDFEG^zLYq5-4#M{EE#c!FlmO4q@sh>8& UE8`98Z8E)Z)q9@cXNOlL3ICFIxBvhE literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..733385fc6a7ad313e439881ab076c0ddcf8989cc GIT binary patch literal 1498 zcmZvXdorSg~- z-6A(NX;P_BqETqWrrpb|2g_-N=DPoPKHopS-+w;meEqz4?UEV+K)_C_&mkY;-sj7m z(D*nS5%r>~7`wA2Q>O}1|K7p7UsY8sjBM{;#61HXnArLXg3HowXP_`zcBn+IOWv@Q zCBIpH+^PzBQLu51`R(`jVlC44RgaS)#_q32N*j;`uxupdFE0N(4?TvYI0BBv9R5WL zo5G&WgJD2?00TynK@<+)003kV+SXw644r6*oP{!!p$f%%jG-+;VNZtvPoiQD0qzE- z9BTmRbcMpnpc%3!6clJ|`nheIAUD{UBbh|3|VA5~L$|i@vBE4(^=GG9dp5`86N6 zmTVDvp;!TSJ*;G0jeDf201o^6?sMdQ?fChW)DXzN2W>2czFX3mjs4l~jX&O@S=*&+ zH_n&0JtS_t_5EdnDKh<jvFL6GwUXy3w|7+LTpif%O&Yi8e*V}L zt*;u1v&zU2J3PCLu0RzUS^{5m1N{fyuj2&or8YZbf2({E^sVsvt<<&{6AfAm*fUt( z7f|2aExRA?w$9K)6ira*!K>`XAQhlS(WOfQlnTOj z4G#*n{Z}b&x#uc;8xpM<4)je3FS87Kx1)2|BR_@11@KL4dWX6lx5nXVxC^GG=CP5r zEvw>t@?E#RnKruh4^5+H{>+Zrf;n(dn8^$zU1N9ou2X+)dnHs>9%@!nOoRkSaO|Ws zVb`A4A`wJ-!2`mHKX-!YQMZ>KV5q*?_&Dq6P#vSiMXPvA6S_Tw=w+@o$~og^^t0tT z597watySJNW+}$JmuDBODAvrxezFYI>xGug+Cx+t9FxtqnH^$Vh_*RC;k>pX*xRB8 zsB@#F7<8-B91_`5h@&$L(rmwlK`iNU{sr9hPt%*$XloNOgwI7>m0hq!V101#KI&;= zu6U1U>H1c6dQ+gLpOZt}oZBQ@mUO2_nlS^c2AV3Jrlo&Qmgbza3hc|r7B@tKeWCS3 z2tnUesD0a%?cnZJ6RZ7tVG2?$uXlsMaPahM3|!l*4X;e(j(&`(xn}f(@{w}go!`|b z?l>(;GQc=JFseDW!Qa5C&)^9>@UnYd66|#s>)cfi7$`q*HuO{$N=Tmi zSwC0|W_el)Ja9i&(-D-$MbV;t`w`P7?LN>z{7T|{^Bvb{ZvQxjJ1OI@KKEyF z2qSH>k+KwMxN;^>UA@$vsN&hoAO1d0#e_wEDGvx!g+7AYWkah39e`9*Nkfn{{x<3)~Emg literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..dee8bac7e0f157a5fd583e952479c7fc75f9fc3a GIT binary patch literal 9012 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 aFun*1hP!fT);iI}rUpgaERxB4ryBsFy&Jdy literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..1299838 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..9a3c1bf --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,19 @@ + + + #FF000000 + #FFFFFFFF + + + @android:color/system_accent1_600 + @android:color/system_accent1_0 + @android:color/system_accent1_100 + @android:color/system_accent1_900 + + @android:color/system_accent2_600 + @android:color/system_accent2_0 + @android:color/system_accent2_100 + @android:color/system_accent2_900 + + @android:color/system_neutral1_50 + @android:color/system_neutral1_900 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..665ca8d --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Calculator + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..b6c7067 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,24 @@ + + + + +