├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml ├── migrations.xml ├── runConfigurations.xml └── vcs.xml ├── ENCRYPTION.md ├── ENCRYPTION_V1.md ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── se │ │ └── arctosoft │ │ └── valv │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── se │ │ │ └── arctosoft │ │ │ └── vault │ │ │ ├── BottomSheetCopyFragment.java │ │ │ ├── BottomSheetDeleteFragment.java │ │ │ ├── BottomSheetExportFragment.java │ │ │ ├── BottomSheetImportFragment.java │ │ │ ├── BottomSheetMoveFragment.java │ │ │ ├── DirectoryAllFragment.java │ │ │ ├── DirectoryBaseFragment.java │ │ │ ├── DirectoryFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── PasswordFragment.java │ │ │ ├── SettingsFragment.java │ │ │ ├── adapters │ │ │ ├── GalleryGridAdapter.java │ │ │ ├── GalleryPagerAdapter.java │ │ │ ├── ImportListAdapter.java │ │ │ └── viewholders │ │ │ │ ├── GalleryGridViewHolder.java │ │ │ │ ├── GalleryPagerViewHolder.java │ │ │ │ └── ImportListViewHolder.java │ │ │ ├── data │ │ │ ├── CursorFile.java │ │ │ ├── FileType.java │ │ │ ├── GalleryFile.java │ │ │ ├── Password.java │ │ │ ├── ProgressData.java │ │ │ ├── StoredDirectory.java │ │ │ └── UniqueLinkedList.java │ │ │ ├── encryption │ │ │ ├── Encryption.java │ │ │ ├── MyCipherInputStream.java │ │ │ ├── MyDataSource.java │ │ │ └── MyDataSourceFactory.java │ │ │ ├── exception │ │ │ └── InvalidPasswordException.java │ │ │ ├── fastscroll │ │ │ ├── LICENSE.md │ │ │ ├── NOTICE │ │ │ ├── OnFastScrollStateChangeListener.java │ │ │ ├── Utils.java │ │ │ └── views │ │ │ │ ├── FastScrollPopup.java │ │ │ │ ├── FastScrollRecyclerView.java │ │ │ │ └── FastScroller.java │ │ │ ├── interfaces │ │ │ ├── IOnAdapterItemChanged.java │ │ │ ├── IOnDirectoryAdded.java │ │ │ ├── IOnDone.java │ │ │ ├── IOnEdited.java │ │ │ ├── IOnFileClicked.java │ │ │ ├── IOnFileDeleted.java │ │ │ ├── IOnFileOperationDone.java │ │ │ ├── IOnImportDone.java │ │ │ ├── IOnProgress.java │ │ │ └── IOnSelectionModeChanged.java │ │ │ ├── loader │ │ │ ├── CipherDataFetcher.java │ │ │ ├── CipherModelLoader.java │ │ │ ├── CipherModelLoaderFactory.java │ │ │ └── MyAppGlideModule.java │ │ │ ├── subsampling │ │ │ ├── ImageSource.java │ │ │ ├── ImageViewState.java │ │ │ ├── MySubsamplingScaleImageView.java │ │ │ └── decoder │ │ │ │ ├── CompatDecoderFactory.java │ │ │ │ ├── DecoderFactory.java │ │ │ │ ├── ImageDecoder.java │ │ │ │ ├── ImageRegionDecoder.java │ │ │ │ ├── SkiaImageDecoder.java │ │ │ │ ├── SkiaImageRegionDecoder.java │ │ │ │ └── SkiaPooledImageRegionDecoder.java │ │ │ ├── utils │ │ │ ├── Constants.java │ │ │ ├── Dialogs.java │ │ │ ├── FileStuff.java │ │ │ ├── GlideStuff.java │ │ │ ├── Pixels.java │ │ │ ├── Settings.java │ │ │ ├── StringStuff.java │ │ │ └── Toaster.java │ │ │ ├── viewmodel │ │ │ ├── CopyViewModel.java │ │ │ ├── DeleteViewModel.java │ │ │ ├── ExportViewModel.java │ │ │ ├── GalleryViewModel.java │ │ │ ├── ImportViewModel.java │ │ │ ├── MoveViewModel.java │ │ │ ├── PasswordViewModel.java │ │ │ └── ShareViewModel.java │ │ │ └── views │ │ │ ├── GridImageView.java │ │ │ ├── PressableConstraintLayout.java │ │ │ ├── PressableGridTextView.java │ │ │ ├── PressableImageView.java │ │ │ └── PressableRelativeLayout.java │ └── res │ │ ├── drawable │ │ ├── ic_baseline_folder_24.xml │ │ ├── ic_baseline_play_arrow_24.xml │ │ ├── ic_baseline_select_all_24.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_outline_create_new_folder_24.xml │ │ ├── ic_outline_delete_forever_24.xml │ │ ├── ic_outline_file_download_24.xml │ │ ├── ic_outline_image_24.xml │ │ ├── ic_outline_library_add_24.xml │ │ ├── ic_outline_lock_24.xml │ │ ├── ic_outline_tips_and_updates_24.xml │ │ ├── ic_outline_video_file_24.xml │ │ ├── ic_round_folder_open_24.xml │ │ ├── ic_round_fullscreen_24.xml │ │ ├── ic_round_gif_24.xml │ │ ├── ic_round_lock_open_24.xml │ │ ├── ic_round_remove_circle_outline_24.xml │ │ ├── ic_round_view_compact_24.xml │ │ ├── line_divider.xml │ │ ├── logo.png │ │ ├── outline_add_photo_alternate_24.xml │ │ ├── outline_broken_image_24.xml │ │ ├── outline_drive_file_move_24.xml │ │ ├── outline_file_copy_24.xml │ │ ├── outline_hide_image_24.xml │ │ ├── outline_sd_storage_24.xml │ │ ├── outline_text_snippet_24.xml │ │ ├── round_add_24.xml │ │ ├── round_all_inclusive_24.xml │ │ ├── round_edit_24.xml │ │ ├── round_expand_less_24.xml │ │ ├── round_expand_more_24.xml │ │ ├── round_filter_list_24.xml │ │ ├── round_key_24.xml │ │ ├── round_more_vert_24.xml │ │ └── round_sort_24.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── adapter_gallery_grid_item.xml │ │ ├── adapter_gallery_viewpager_item.xml │ │ ├── adapter_gallery_viewpager_item_directory.xml │ │ ├── adapter_gallery_viewpager_item_gif.xml │ │ ├── adapter_gallery_viewpager_item_image.xml │ │ ├── adapter_gallery_viewpager_item_text.xml │ │ ├── adapter_gallery_viewpager_item_video.xml │ │ ├── adapter_import_list_item.xml │ │ ├── bottom_sheet_copy.xml │ │ ├── bottom_sheet_delete.xml │ │ ├── bottom_sheet_export.xml │ │ ├── bottom_sheet_import.xml │ │ ├── dialog_edit_note.xml │ │ ├── dialog_import.xml │ │ ├── dialog_import_text.xml │ │ ├── dialog_set_iteration_count.xml │ │ ├── fragment_directory.xml │ │ ├── fragment_password.xml │ │ ├── image_item.xml │ │ └── loading_item.xml │ │ ├── menu │ │ ├── menu_dir.xml │ │ ├── menu_gallery_viewpager.xml │ │ ├── menu_main_selection_dir.xml │ │ ├── menu_main_selection_root.xml │ │ └── menu_root.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher_v.xml │ │ └── ic_launcher_v_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher_v.png │ │ ├── ic_launcher_v_background.png │ │ ├── ic_launcher_v_foreground.png │ │ └── ic_launcher_v_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher_v.png │ │ ├── ic_launcher_v_background.png │ │ ├── ic_launcher_v_foreground.png │ │ └── ic_launcher_v_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher_v.png │ │ ├── ic_launcher_v_background.png │ │ ├── ic_launcher_v_foreground.png │ │ └── ic_launcher_v_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher_v.png │ │ ├── ic_launcher_v_background.png │ │ ├── ic_launcher_v_foreground.png │ │ └── ic_launcher_v_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher_v.png │ │ ├── ic_launcher_v_background.png │ │ ├── ic_launcher_v_foreground.png │ │ └── ic_launcher_v_round.png │ │ ├── navigation │ │ └── nav_graph.xml │ │ ├── values-land │ │ └── dimens.xml │ │ ├── values-night │ │ ├── bool.xml │ │ └── themes.xml │ │ ├── values-w1240dp │ │ └── dimens.xml │ │ ├── values-w600dp │ │ └── dimens.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── bool.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ ├── provider_paths.xml │ │ └── root_preferences.xml │ └── test │ └── java │ └── se │ └── arctosoft │ └── valv │ └── ExampleUnitTest.java ├── build.gradle.kts ├── config ├── libraries │ ├── lib_fastscroll.json │ └── lib_subsampling.json └── licenses │ └── lic_fastscroll.json ├── fastlane ├── .gitignore ├── Appfile ├── Fastfile ├── README.md └── metadata │ └── android │ ├── en-US │ ├── changelogs │ │ ├── 14.txt │ │ ├── 15.txt │ │ ├── 16.txt │ │ ├── 17.txt │ │ ├── 18.txt │ │ ├── 19.txt │ │ ├── 20.txt │ │ ├── 21.txt │ │ ├── 23.txt │ │ ├── 24.txt │ │ ├── 25.txt │ │ ├── 26.txt │ │ ├── 27.txt │ │ ├── 28.txt │ │ ├── 29.txt │ │ ├── 30.txt │ │ ├── 31.txt │ │ ├── 32.txt │ │ ├── 33.txt │ │ ├── 34.txt │ │ ├── 35.txt │ │ ├── 36.txt │ │ └── 37.txt │ ├── full_description.txt │ ├── images │ │ ├── featureGraphic.png │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ └── 3.jpg │ ├── short_description.txt │ └── title.txt │ └── sv-SE │ ├── changelogs │ ├── 14.txt │ ├── 15.txt │ ├── 16.txt │ ├── 17.txt │ ├── 18.txt │ ├── 19.txt │ ├── 20.txt │ ├── 21.txt │ ├── 23.txt │ ├── 24.txt │ ├── 25.txt │ ├── 26.txt │ ├── 27.txt │ ├── 28.txt │ ├── 29.txt │ ├── 30.txt │ ├── 31.txt │ ├── 32.txt │ ├── 33.txt │ ├── 34.txt │ ├── 35.txt │ ├── 36.txt │ └── 37.txt │ ├── full_description.txt │ ├── images │ ├── featureGraphic.png │ ├── icon.png │ └── phoneScreenshots │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ └── 3.jpg │ ├── short_description.txt │ └── title.txt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── encryption_v1.jpg └── encryption_v2.jpg └── settings.gradle.kts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: hej2010 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: hej2010 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['https://arctosoft.com/donate/'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] - " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE REQUEST] - " 5 | labels: 'Feature request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/copyright 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | /.idea/misc.xml 12 | /.idea/statistic.xml 13 | .DS_Store 14 | /build 15 | /captures 16 | .externalNativeBuild 17 | .cxx 18 | local.properties 19 | /app/release/ 20 | /.idea/deploymentTargetDropDown.xml 21 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | /other.xml 5 | deploymentTargetSelector.xml -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ENCRYPTION.md: -------------------------------------------------------------------------------- 1 | This is the encryption docs for file structure version 2. 2 | 3 | # File encryption 4 | Files are encrypted using the `ChaCha20/NONE/NoPadding` cipher in Android. See [Android Ciphers](https://developer.android.com/reference/javax/crypto/Cipher) for details. 5 | 6 | The key algorithm is `PBKDF2withHmacSHA512` with 50000 iterations (default, can be changed) and a 256-bit key length. 7 | 8 | The salt is 16 bytes and the IV is 12 bytes. An additional 12 bytes is used to check if the supplied password can decrypt the file, see details below. 9 | 10 | ## Encrypted file structure 11 | ![Encrypted file structure image](/images/encryption_v2.jpg) 12 | 13 | ## File types/names 14 | 15 | The following filename suffixes are used: 16 | - `-i.valv` for image files 17 | - `-g.valv` for GIF files 18 | - `-v.valv` for video files 19 | - `-x.valv` for text files 20 | - `-n.valv` for note files 21 | - `-t.valv` for thumbnail files 22 | 23 | Filenames are generated randomly and are `32 chars + SUFFIX_LENGTH` long. 24 | Every media file has a corresponding thumbnail with the same name. For example, an image file named 25 | 26 | `aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ-i.valv` has a thumbnail 27 | 28 | `aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ-t.valv`. 29 | 30 | Similarly, a note has the same name as its media file. 31 | 32 | All text and strings are encoded as UTF-8. 33 | 34 | ## Encrypting 35 | The app creates the encrypted files in the following way: 36 | 1. Generate a random 16 byte salt, a 12 byte IV and 12 check bytes. 37 | 2. Create an unencrypted output stream. 38 | 3. Write the encrypted file structure version (4 bytes, integer) 39 | 4. Write the salt. 40 | 5. Write the IV. 41 | 6. Write the iteration count used for key generation (4 bytes, integer) 42 | 7. Write the check bytes. 43 | 8. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted. 44 | 9. Write the check bytes. 45 | 10. Write a newline character followed by a JSON object as an string containing the original filename and another newline character (`'\n' + "{\"originalName\":\"file.jpg\"}" + '\n'`). 46 | 11. Write the file data. 47 | 48 | ## Decrypting 49 | The app reads the encrypted files in the following way: 50 | 1. Create an unencrypted input stream. 51 | 2. Read the encrypted file structure version (4 bytes, integer) 52 | 3. Read the 16 byte salt. 53 | 4. Read the 12 byte IV. 54 | 5. Read the iteration count used for key generation (4 bytes, integer) 55 | 6. Read the 12 check bytes. 56 | 7. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data. 57 | 8. Read the check bytes. If the unencrypted check bytes does not equal the check bytes in the encrypted part, the given password is invalid. 58 | 9. Read a newline character (`0x0A`) followed by the JSON object string and another newline character. 59 | 10. Read the file data. 60 | 61 | -------------------------------------------------------------------------------- /ENCRYPTION_V1.md: -------------------------------------------------------------------------------- 1 | This is the encryption docs for file structure version 1. 2 | 3 | # File encryption 4 | Files are encrypted using the `ChaCha20/NONE/NoPadding` cipher in Android. See [Android Ciphers](https://developer.android.com/reference/javax/crypto/Cipher) for details. 5 | 6 | The key algorithm is `PBKDF2withHmacSHA512` with 20000 iterations and a 256-bit key length. 7 | 8 | The salt is 16 bytes and the IV is 12 bytes. An additional 12 bytes is used in some files to check if the supplied password can decrypt the file, see details below. 9 | 10 | ## Encrypted file structure 11 | ![Encrypted file structure image](/images/encryption_v1.jpg) 12 | 13 | ## File types/names 14 | 15 | The following filename prefixes are used: 16 | - `.valv.i.1-` for image files 17 | - `.valv.g.1-` for GIF files 18 | - `.valv.v.1-` for video files 19 | - `.valv.x.1-` for text files 20 | - `.valv.n.1-` for note files 21 | - `.valv.t.1-` for thumbnail files 22 | 23 | The number represents the file structure version (for future expansion/changes). 24 | 25 | Filenames are generated randomly and are `PREFIX_LENGTH + 32 chars` long. 26 | Every media file has a corresponding thumbnail with the same name. For example, an image file named 27 | 28 | `.valv.i.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ` has a thumbnail 29 | 30 | `.valv.t.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ`. 31 | 32 | Similarly, a note has the same name as its media file. 33 | 34 | ## Encrypting 35 | The app creates the encrypted files in the following way: 36 | 1. Generate a random 16 byte salt and 12 byte IV. If the file is a thumbnail it also generates an additional 12 check bytes. 37 | 2. Create an unencrypted output stream. 38 | 3. Write the salt. 39 | 4. Write the IV. 40 | 5. If the file is a thumbnail, write the check bytes. 41 | 6. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted. 42 | 7. If the file is a thumbnail, write the check bytes. 43 | 8. Write a newline character followed by the original filename and another newline character (`'\n' + name + '\n'`). 44 | 9. Write the file data. 45 | 46 | ## Decrypting 47 | The app reads the encrypted files in the following way: 48 | 1. Create an unencrypted input stream. 49 | 2. Read the 16 byte salt. 50 | 3. Read the 12 byte IV. 51 | 4. If the file is a thumbnail, read the 12 check bytes. 52 | 5. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data. 53 | 6. If the file is a thumbnail, read the check bytes. If the unencrypted check bytes does not equal the check bytes in the encrypted part, the given password is invalid. 54 | 7. Read a newline character (`0x0A`) followed by the original filename and another newline character. 55 | 8. Read the file data. 56 | 57 | A Python script to decrypt .valv files can be found in [this issue comment](https://github.com/Arctosoft/Valv-Android/issues/33#issuecomment-1974834924). 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Valv 2 | An encrypted gallery vault for Android devices. 3 | 4 | ## Features 5 | - Supports images, GIFs, videos and text files 6 | - Organise using folders 7 | - The app requires no permissions 8 | - Encrypted files are stored on-disk allowing for easy backups and transfers between devices 9 | - Supports multiple vaults by the use of different passwords 10 | - Day/night modes 11 | - Add notes/text to files 12 | 13 | ## Encryption 14 | Files are encrypted using ChaCha20 and keys are derived using PBKDF2 with HMAC-SHA512. Read the details in [ENCRYPTION.md](ENCRYPTION.md). 15 | 16 | ## Get the app 17 | [Download from F-Droid](https://f-droid.org/packages/se.arctosoft.vault/) 20 | [Download from Google Play](https://play.google.com/store/apps/details?id=se.arctosoft.vault) 23 | 24 | Or download the latest APK from the [Releases Section](https://github.com/Arctosoft/Valv-Android/releases/latest). 25 | 26 | ## Requirements 27 | - Android 9 or newer 28 | 29 | ## Screenshots 30 | ![Locked screen](/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg "Locked screen") 31 | ![Gallery](/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg "Gallery") 32 | ![Gallery folder](/fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg "Gallery folder") 33 | 34 | ## 35 | This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 36 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) 3 | alias(libs.plugins.about.libraries) 4 | } 5 | 6 | android { 7 | namespace = "se.arctosoft.vault" 8 | compileSdk = 35 9 | 10 | defaultConfig { 11 | applicationId = "se.arctosoft.vault" 12 | minSdk = 28 13 | targetSdk = 35 14 | versionCode = 37 15 | versionName = "2.2.2" 16 | 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | isMinifyEnabled = true 23 | proguardFiles( 24 | getDefaultProguardFile("proguard-android-optimize.txt"), 25 | "proguard-rules.pro" 26 | ) 27 | } 28 | debug { 29 | isMinifyEnabled = false 30 | proguardFiles( 31 | getDefaultProguardFile("proguard-android-optimize.txt"), 32 | "proguard-rules.pro" 33 | ) 34 | applicationIdSuffix = ".dev" 35 | } 36 | applicationVariants.all { 37 | val variant = this 38 | variant.outputs.map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl } 39 | .forEach { output -> 40 | val outputFileName = 41 | "Vault_${variant.versionCode}_${variant.versionName}_${variant.buildType.name}.apk" 42 | output.outputFileName = outputFileName 43 | } 44 | } 45 | } 46 | compileOptions { 47 | sourceCompatibility = JavaVersion.VERSION_17 48 | targetCompatibility = JavaVersion.VERSION_17 49 | } 50 | buildFeatures { 51 | viewBinding = true 52 | buildConfig = true 53 | } 54 | dependenciesInfo { 55 | // Disables dependency metadata when building APKs. 56 | includeInApk = false 57 | // Disables dependency metadata when building Android App Bundles. 58 | includeInBundle = false 59 | } 60 | } 61 | 62 | dependencies { 63 | androidTestImplementation(libs.ext.junit) 64 | androidTestImplementation(libs.espresso.core) 65 | testImplementation(libs.junit) 66 | 67 | implementation(libs.appcompat) 68 | implementation(libs.material) 69 | implementation(libs.constraintlayout) 70 | implementation(libs.navigation.fragment) 71 | implementation(libs.navigation.ui) 72 | implementation(libs.preference) 73 | implementation(libs.activity) 74 | 75 | implementation(libs.security.crypto) 76 | implementation(libs.media3.exoplayer) 77 | implementation(libs.media3.ui) 78 | implementation(libs.preferences) 79 | annotationProcessor(libs.glide.annotation) 80 | 81 | implementation(libs.glide) 82 | implementation(libs.about.libraries) 83 | implementation(libs.about.libraries.compose) 84 | } 85 | 86 | aboutLibraries { 87 | configPath = "config" 88 | // Remove the "generated" timestamp to allow for reproducible builds 89 | excludeFields = arrayOf("generated") 90 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # remove all log prints 24 | -assumenosideeffects class android.util.Log { 25 | public static boolean isLoggable(java.lang.String, int); 26 | public static int v(...); 27 | public static int d(...); 28 | public static int i(...); 29 | public static int w(...); 30 | public static int e(...); 31 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/se/arctosoft/valv/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("se.arctosoft.vault", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 54 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/PasswordFragment.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault; 2 | 3 | import android.os.Bundle; 4 | import android.text.Editable; 5 | import android.text.TextWatcher; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.inputmethod.EditorInfo; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | import androidx.fragment.app.Fragment; 14 | import androidx.lifecycle.SavedStateHandle; 15 | import androidx.lifecycle.ViewModelProvider; 16 | import androidx.navigation.Navigation; 17 | import androidx.navigation.fragment.NavHostFragment; 18 | 19 | import se.arctosoft.vault.databinding.FragmentPasswordBinding; 20 | import se.arctosoft.vault.utils.Dialogs; 21 | import se.arctosoft.vault.viewmodel.PasswordViewModel; 22 | 23 | public class PasswordFragment extends Fragment { 24 | public static String LOGIN_SUCCESSFUL = "LOGIN_SUCCESSFUL"; 25 | 26 | private PasswordViewModel passwordViewModel; 27 | private SavedStateHandle savedStateHandle; 28 | private FragmentPasswordBinding binding; 29 | 30 | @Override 31 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 32 | binding = FragmentPasswordBinding.inflate(inflater, container, false); 33 | return binding.getRoot(); 34 | } 35 | 36 | @Override 37 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 38 | passwordViewModel = new ViewModelProvider(requireActivity()).get(PasswordViewModel.class); 39 | 40 | savedStateHandle = Navigation.findNavController(view) 41 | .getPreviousBackStackEntry() 42 | .getSavedStateHandle(); 43 | savedStateHandle.set(LOGIN_SUCCESSFUL, false); 44 | 45 | binding.eTPassword.addTextChangedListener(new TextWatcher() { 46 | @Override 47 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 48 | } 49 | 50 | @Override 51 | public void onTextChanged(CharSequence s, int start, int before, int count) { 52 | } 53 | 54 | @Override 55 | public void afterTextChanged(Editable s) { 56 | int length = s.length(); 57 | binding.btnUnlock.setEnabled(length > 0); 58 | } 59 | }); 60 | binding.eTPassword.setOnEditorActionListener((v, actionId, event) -> { 61 | if (actionId == EditorInfo.IME_ACTION_GO || actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_SEND) { 62 | binding.btnUnlock.performClick(); 63 | return true; 64 | } 65 | return false; 66 | }); 67 | binding.btnUnlock.setOnClickListener(v -> { 68 | binding.btnUnlock.setEnabled(false); 69 | char[] temp = new char[binding.eTPassword.length()]; 70 | binding.eTPassword.getText().getChars(0, binding.eTPassword.length(), temp, 0); 71 | passwordViewModel.setPassword(temp); 72 | binding.eTPassword.setText(null); 73 | 74 | MainActivity.GLIDE_KEY = System.currentTimeMillis(); 75 | savedStateHandle.set(LOGIN_SUCCESSFUL, true); 76 | NavHostFragment.findNavController(this).popBackStack(); 77 | }); 78 | binding.btnHelp.setOnClickListener(v -> Dialogs.showTextDialog(requireContext(), null, getString(R.string.launcher_help_message))); 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/adapters/ImportListAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.adapters; 20 | 21 | import android.content.Context; 22 | import android.view.LayoutInflater; 23 | import android.view.ViewGroup; 24 | 25 | import androidx.annotation.NonNull; 26 | import androidx.recyclerview.widget.RecyclerView; 27 | 28 | import java.util.List; 29 | 30 | import se.arctosoft.vault.R; 31 | import se.arctosoft.vault.adapters.viewholders.ImportListViewHolder; 32 | import se.arctosoft.vault.databinding.AdapterImportListItemBinding; 33 | import se.arctosoft.vault.utils.Dialogs; 34 | 35 | public class ImportListAdapter extends RecyclerView.Adapter { 36 | private final List names; 37 | private final Context context; 38 | private final String firstPosName; 39 | private Dialogs.IOnPositionSelected onPositionSelected; 40 | 41 | public ImportListAdapter(List names, Context context, String firstPosName) { 42 | this.names = names; 43 | this.context = context; 44 | this.firstPosName = firstPosName; 45 | } 46 | 47 | public void setOnPositionSelected(Dialogs.IOnPositionSelected onPositionSelected) { 48 | this.onPositionSelected = onPositionSelected; 49 | } 50 | 51 | @NonNull 52 | @Override 53 | public ImportListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 54 | AdapterImportListItemBinding binding = AdapterImportListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); 55 | return new ImportListViewHolder(binding); 56 | } 57 | 58 | @Override 59 | public void onBindViewHolder(@NonNull ImportListViewHolder holder, int position) { 60 | if (position == 0 && firstPosName != null) { 61 | holder.binding.text.setText(context.getString(R.string.modal_current_folder, firstPosName)); 62 | } else { 63 | holder.binding.text.setText(context.getString(R.string.modal_directory_item, names.get(position))); 64 | } 65 | holder.binding.text.setOnClickListener(v -> onPositionSelected.onSelected(position)); 66 | } 67 | 68 | @Override 69 | public int getItemCount() { 70 | return names.size(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/adapters/viewholders/GalleryGridViewHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.adapters.viewholders; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.recyclerview.widget.RecyclerView; 23 | 24 | import se.arctosoft.vault.databinding.AdapterGalleryGridItemBinding; 25 | 26 | public class GalleryGridViewHolder extends RecyclerView.ViewHolder { 27 | public final AdapterGalleryGridItemBinding binding; 28 | 29 | public GalleryGridViewHolder(@NonNull AdapterGalleryGridItemBinding binding) { 30 | super(binding.getRoot()); 31 | this.binding = binding; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/adapters/viewholders/ImportListViewHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.adapters.viewholders; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.recyclerview.widget.RecyclerView; 23 | 24 | import se.arctosoft.vault.databinding.AdapterImportListItemBinding; 25 | 26 | public class ImportListViewHolder extends RecyclerView.ViewHolder { 27 | public final AdapterImportListItemBinding binding; 28 | 29 | public ImportListViewHolder(@NonNull AdapterImportListItemBinding binding) { 30 | super(binding.getRoot()); 31 | this.binding = binding; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/data/CursorFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.data; 20 | 21 | import android.net.Uri; 22 | import android.provider.DocumentsContract; 23 | 24 | public class CursorFile implements Comparable { 25 | private final String name; 26 | private final Uri uri; 27 | private final long lastModified, size; 28 | private final String mimeType; 29 | private final boolean isDirectory; 30 | private String nameWithoutPrefix; 31 | 32 | public CursorFile(String name, Uri uri, long lastModified, String mimeType, long size) { 33 | this.name = name; 34 | this.uri = uri; 35 | this.mimeType = mimeType; 36 | this.size = size; 37 | this.isDirectory = DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType); 38 | this.lastModified = lastModified; 39 | } 40 | 41 | public void setNameWithoutPrefix(String nameWithoutPrefix) { 42 | this.nameWithoutPrefix = nameWithoutPrefix; 43 | } 44 | 45 | public long getSize() { 46 | return size; 47 | } 48 | 49 | public String getNameWithoutPrefix() { 50 | return nameWithoutPrefix; 51 | } 52 | 53 | public boolean isDirectory() { 54 | return isDirectory; 55 | } 56 | 57 | public String getName() { 58 | return name; 59 | } 60 | 61 | public Uri getUri() { 62 | return uri; 63 | } 64 | 65 | public long getLastModified() { 66 | return lastModified; 67 | } 68 | 69 | public String getMimeType() { 70 | return mimeType; 71 | } 72 | 73 | @Override 74 | public int compareTo(CursorFile o) { 75 | return Long.compare(o.lastModified, this.lastModified); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/data/FileType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.data; 20 | 21 | import androidx.annotation.NonNull; 22 | 23 | import se.arctosoft.vault.encryption.Encryption; 24 | 25 | public enum FileType { 26 | DIRECTORY(0, null, null, 1), 27 | IMAGE_V1(1, ".jpg", Encryption.PREFIX_IMAGE_FILE, 1), 28 | IMAGE_V2(1, ".jpg", Encryption.SUFFIX_IMAGE_FILE, 2), 29 | GIF_V1(2, ".gif", Encryption.PREFIX_GIF_FILE, 1), 30 | GIF_V2(2, ".gif", Encryption.SUFFIX_GIF_FILE, 2), 31 | VIDEO_V1(3, ".mp4", Encryption.PREFIX_VIDEO_FILE, 1), 32 | VIDEO_V2(3, ".mp4", Encryption.SUFFIX_VIDEO_FILE, 2), 33 | TEXT_V1(4, ".txt", Encryption.PREFIX_TEXT_FILE, 1), 34 | TEXT_V2(4, ".txt", Encryption.SUFFIX_TEXT_FILE, 2); 35 | 36 | public static final int TYPE_DIRECTORY = 0; 37 | public static final int TYPE_IMAGE = 1; 38 | public static final int TYPE_GIF = 2; 39 | public static final int TYPE_VIDEO = 3; 40 | public static final int TYPE_TEXT = 4; 41 | 42 | public final String extension, suffixPrefix; 43 | public final int type, version; 44 | 45 | FileType(int type, String extension, String suffixPrefix, int version) { 46 | this.type = type; 47 | this.extension = extension; 48 | this.suffixPrefix = suffixPrefix; 49 | this.version = version; 50 | } 51 | 52 | public static FileType fromFilename(@NonNull String name) { 53 | if (name.startsWith(Encryption.PREFIX_IMAGE_FILE)) { 54 | return IMAGE_V1; 55 | } else if (name.endsWith(Encryption.SUFFIX_IMAGE_FILE)) { 56 | return IMAGE_V2; 57 | } else if (name.startsWith(Encryption.PREFIX_GIF_FILE)) { 58 | return GIF_V1; 59 | } else if (name.endsWith(Encryption.SUFFIX_GIF_FILE)) { 60 | return GIF_V2; 61 | } else if (name.startsWith(Encryption.PREFIX_VIDEO_FILE)) { 62 | return VIDEO_V1; 63 | } else if (name.endsWith(Encryption.SUFFIX_VIDEO_FILE)) { 64 | return VIDEO_V2; 65 | } else if (name.startsWith(Encryption.PREFIX_TEXT_FILE)) { 66 | return TEXT_V1; 67 | } else if (name.endsWith(Encryption.SUFFIX_TEXT_FILE)) { 68 | return TEXT_V2; 69 | } else { 70 | return DIRECTORY; 71 | } 72 | } 73 | 74 | public boolean isDirectory() { 75 | return this == DIRECTORY; 76 | } 77 | 78 | public boolean isImage() { 79 | return this == IMAGE_V1 || this == IMAGE_V2; 80 | } 81 | 82 | public boolean isGif() { 83 | return this == GIF_V1 || this == GIF_V2; 84 | } 85 | 86 | 87 | public boolean isVideo() { 88 | return this == VIDEO_V1 || this == VIDEO_V2; 89 | } 90 | 91 | public boolean isText() { 92 | return this == TEXT_V1 || this == TEXT_V2; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/data/Password.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2023 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.data; 20 | 21 | import android.content.Context; 22 | import android.util.Log; 23 | 24 | import com.bumptech.glide.Glide; 25 | 26 | import java.util.Arrays; 27 | 28 | import se.arctosoft.vault.MainActivity; 29 | import se.arctosoft.vault.utils.FileStuff; 30 | 31 | public class Password { 32 | private static final String TAG = "Password"; 33 | 34 | private static Password instance; 35 | private char[] password; 36 | 37 | private Password() { 38 | } 39 | 40 | public void setPassword(char[] password) { 41 | this.password = password; 42 | } 43 | 44 | public char[] getPassword() { 45 | return password; 46 | } 47 | 48 | public static Password getInstance() { 49 | if (instance == null) { 50 | instance = new Password(); 51 | } 52 | return instance; 53 | } 54 | 55 | public void clearPassword() { 56 | if (password != null) { 57 | Arrays.fill(password, (char) 0); 58 | password = null; 59 | } 60 | } 61 | 62 | public static void lock(Context context) { 63 | Log.d(TAG, "lock"); 64 | Password p = Password.getInstance(); 65 | p.clearPassword(); 66 | if (context != null) { 67 | FileStuff.deleteCache(context); 68 | Glide.get(context).clearMemory(); 69 | } 70 | //new Thread(() -> Glide.get(context).clearDiskCache()).start(); 71 | MainActivity.GLIDE_KEY = System.currentTimeMillis(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/data/ProgressData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.data; 19 | 20 | public class ProgressData { 21 | private final int total, progress, progressPercentage; 22 | private final String doneMB, totalMB; 23 | 24 | public ProgressData(int total, int progress, int progressPercentage, String doneMB, String totalMB) { 25 | this.total = total; 26 | this.progress = progress; 27 | this.progressPercentage = progressPercentage; 28 | this.doneMB = doneMB; 29 | this.totalMB = totalMB; 30 | } 31 | 32 | public int getTotal() { 33 | return total; 34 | } 35 | 36 | public int getProgress() { 37 | return progress; 38 | } 39 | 40 | public int getProgressPercentage() { 41 | return progressPercentage; 42 | } 43 | 44 | public String getDoneMB() { 45 | return doneMB; 46 | } 47 | 48 | public String getTotalMB() { 49 | return totalMB; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/data/StoredDirectory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.data; 20 | 21 | import android.net.Uri; 22 | 23 | import androidx.annotation.NonNull; 24 | 25 | import java.util.Objects; 26 | 27 | public class StoredDirectory { 28 | private final String uriString; 29 | private final Uri uri; 30 | private final boolean rootDir; 31 | 32 | public StoredDirectory(String uriString, boolean rootDir) { 33 | this.uriString = uriString; 34 | this.uri = Uri.parse(uriString); 35 | this.rootDir = rootDir; 36 | } 37 | 38 | public StoredDirectory(@NonNull Uri uri, boolean rootDir) { 39 | this.uriString = uri.toString(); 40 | this.uri = uri; 41 | this.rootDir = rootDir; 42 | } 43 | 44 | public String getUriString() { 45 | return uriString; 46 | } 47 | 48 | public Uri getUri() { 49 | return uri; 50 | } 51 | 52 | public boolean isRootDir() { 53 | return rootDir; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (o == null || getClass() != o.getClass()) return false; 60 | StoredDirectory that = (StoredDirectory) o; 61 | return uri.equals(that.uri) || uriString.equals(that.uriString); 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return Objects.hash(uri); 67 | } 68 | 69 | @NonNull 70 | @Override 71 | public String toString() { 72 | return (rootDir ? '1' : '0') + uriString; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/encryption/MyDataSourceFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.encryption; 20 | 21 | import android.content.Context; 22 | 23 | import androidx.annotation.NonNull; 24 | import androidx.annotation.OptIn; 25 | import androidx.media3.datasource.DataSource; 26 | 27 | import se.arctosoft.vault.data.Password; 28 | import se.arctosoft.vault.viewmodel.PasswordViewModel; 29 | 30 | public class MyDataSourceFactory implements DataSource.Factory { 31 | private final Context context; 32 | private final int version; 33 | private final Password password; 34 | 35 | public MyDataSourceFactory(Context context, int version, Password password) { 36 | this.context = context; 37 | this.version = version; 38 | this.password = password; 39 | } 40 | 41 | @OptIn(markerClass = androidx.media3.common.util.UnstableApi.class) 42 | @NonNull 43 | @Override 44 | public DataSource createDataSource() { 45 | return new MyDataSource(context, version, password); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/exception/InvalidPasswordException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.exception; 20 | 21 | public class InvalidPasswordException extends Exception { 22 | 23 | public InvalidPasswordException() { 24 | } 25 | 26 | public InvalidPasswordException(String message) { 27 | super(message); 28 | } 29 | 30 | public InvalidPasswordException(Throwable cause) { 31 | super(cause); 32 | } 33 | 34 | public InvalidPasswordException(String message, Throwable cause) { 35 | super(message, cause); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/fastscroll/LICENSE.md: -------------------------------------------------------------------------------- 1 | ### Licenses (for the `fastscroll` folder) 2 | 3 | RecyclerView-FastScroll 4 | 5 | Copyright (C) 2016 Tim Malseed 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | 19 | Launcher 3: 20 | 21 | Copyright (C) 2010 The Android Open Source Project 22 | 23 | Licensed under the Apache License, Version 2.0 (the "License"); 24 | you may not use this file except in compliance with the License. 25 | You may obtain a copy of the License at 26 | 27 | http://www.apache.org/licenses/LICENSE-2.0 28 | 29 | Unless required by applicable law or agreed to in writing, software 30 | distributed under the License is distributed on an "AS IS" BASIS, 31 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 32 | See the License for the specific language governing permissions and 33 | limitations under the License. -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/fastscroll/OnFastScrollStateChangeListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Tim Malseed 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package se.arctosoft.vault.fastscroll; 17 | 18 | public interface OnFastScrollStateChangeListener { 19 | 20 | /** 21 | * Called when fast scrolling begins 22 | */ 23 | void onFastScrollStart(); 24 | 25 | /** 26 | * Called when fast scrolling ends 27 | */ 28 | void onFastScrollStop(); 29 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/fastscroll/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Tim Malseed 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package se.arctosoft.vault.fastscroll; 17 | 18 | import android.content.res.Resources; 19 | import android.util.TypedValue; 20 | import android.view.View; 21 | 22 | public class Utils { 23 | /** 24 | * Converts dp to px 25 | * 26 | * @param res Resources 27 | * @param dp the value in dp 28 | * @return int 29 | */ 30 | public static int toPixels(Resources res, float dp) { 31 | return (int) (dp * res.getDisplayMetrics().density); 32 | } 33 | 34 | /** 35 | * Converts sp to px 36 | * 37 | * @param res Resources 38 | * @param sp the value in sp 39 | * @return int 40 | */ 41 | public static int toScreenPixels(Resources res, float sp) { 42 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, res.getDisplayMetrics()); 43 | } 44 | 45 | public static boolean isRtl(Resources res) { 46 | return res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnAdapterItemChanged.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.interfaces; 19 | 20 | public interface IOnAdapterItemChanged { 21 | void onChanged(int pos); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnDirectoryAdded.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.interfaces; 20 | 21 | public interface IOnDirectoryAdded { 22 | void onAdded(); 23 | 24 | void onAddedAsRoot(); 25 | 26 | void onAlreadyExists(); 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnDone.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.interfaces; 19 | 20 | public interface IOnDone { 21 | void onDone(); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnEdited.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.interfaces; 20 | 21 | import androidx.annotation.Nullable; 22 | 23 | public interface IOnEdited { 24 | void onEdited(@Nullable String text); 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnFileClicked.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.interfaces; 20 | 21 | public interface IOnFileClicked { 22 | void onClick(int pos); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnFileDeleted.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.interfaces; 20 | 21 | public interface IOnFileDeleted { 22 | void onFileDeleted(int pos); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnFileOperationDone.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.interfaces; 19 | 20 | import java.util.List; 21 | 22 | import se.arctosoft.vault.data.GalleryFile; 23 | 24 | public interface IOnFileOperationDone { 25 | void onDone(List processedFiles); 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnImportDone.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.interfaces; 19 | 20 | import android.net.Uri; 21 | 22 | public interface IOnImportDone { 23 | void onDone(Uri destinationUri, boolean isSameDirectory, int importedCount, int failedCount, int thumbErrorCount); 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnProgress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.interfaces; 20 | 21 | public interface IOnProgress { 22 | void onProgress(long progress); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/interfaces/IOnSelectionModeChanged.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.interfaces; 20 | 21 | public interface IOnSelectionModeChanged { 22 | void onSelectionModeChanged(boolean inSelectionMode); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/loader/CipherDataFetcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.loader; 20 | 21 | import android.content.Context; 22 | import android.net.Uri; 23 | 24 | import androidx.annotation.NonNull; 25 | 26 | import com.bumptech.glide.Priority; 27 | import com.bumptech.glide.load.DataSource; 28 | import com.bumptech.glide.load.data.DataFetcher; 29 | 30 | import org.json.JSONException; 31 | 32 | import java.io.IOException; 33 | import java.io.InputStream; 34 | import java.security.GeneralSecurityException; 35 | 36 | import se.arctosoft.vault.data.FileType; 37 | import se.arctosoft.vault.data.Password; 38 | import se.arctosoft.vault.encryption.Encryption; 39 | import se.arctosoft.vault.exception.InvalidPasswordException; 40 | 41 | public class CipherDataFetcher implements DataFetcher { 42 | private static final String TAG = "CipherDataFetcher"; 43 | private Encryption.Streams streams; 44 | private final Context context; 45 | private final Uri uri; 46 | private final int version; 47 | private final Password password; 48 | 49 | public CipherDataFetcher(@NonNull Context context, Uri uri, int version) { 50 | this.context = context.getApplicationContext(); 51 | this.uri = uri; 52 | this.version = version; 53 | this.password = Password.getInstance(); 54 | } 55 | 56 | @Override 57 | public void loadData(@NonNull Priority priority, @NonNull DataCallback callback) { 58 | try { 59 | InputStream inputStream = context.getContentResolver().openInputStream(uri); 60 | streams = Encryption.getCipherInputStream( 61 | inputStream, 62 | password.getPassword(), 63 | version > 1 || !uri.getLastPathSegment().contains(FileType.GIF_V1.suffixPrefix), // don't load as thumb for GIF file 64 | version 65 | ); 66 | callback.onDataReady(streams.getInputStream()); 67 | } catch (GeneralSecurityException | IOException | InvalidPasswordException | 68 | JSONException e) { 69 | //e.printStackTrace(); 70 | callback.onLoadFailed(e); 71 | } 72 | } 73 | 74 | @Override 75 | public void cleanup() { 76 | cancel(); 77 | } 78 | 79 | @Override 80 | public void cancel() { 81 | if (streams != null) { 82 | streams.close(); // interrupts decode if any 83 | } 84 | } 85 | 86 | @NonNull 87 | @Override 88 | public Class getDataClass() { 89 | return InputStream.class; 90 | } 91 | 92 | @NonNull 93 | @Override 94 | public DataSource getDataSource() { 95 | return DataSource.LOCAL; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/loader/CipherModelLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.loader; 20 | 21 | import android.content.Context; 22 | import android.net.Uri; 23 | 24 | import androidx.annotation.NonNull; 25 | import androidx.annotation.Nullable; 26 | 27 | import com.bumptech.glide.load.Options; 28 | import com.bumptech.glide.load.model.ModelLoader; 29 | import com.bumptech.glide.signature.ObjectKey; 30 | 31 | import java.io.InputStream; 32 | 33 | import se.arctosoft.vault.encryption.Encryption; 34 | 35 | public class CipherModelLoader implements ModelLoader { 36 | private final Context context; 37 | private final int version; 38 | 39 | public CipherModelLoader(@NonNull Context context, int version) { 40 | this.context = context.getApplicationContext(); 41 | this.version = version; 42 | } 43 | 44 | @Nullable 45 | @Override 46 | public LoadData buildLoadData(@NonNull Uri uri, int width, int height, @NonNull Options options) { 47 | return new LoadData<>(new ObjectKey(uri), new CipherDataFetcher(context, uri, version)); 48 | } 49 | 50 | @Override 51 | public boolean handles(@NonNull Uri uri) { 52 | String lastSegment = uri.getLastPathSegment(); 53 | if (version < 2) { 54 | return lastSegment != null && lastSegment.toLowerCase().contains("/" + Encryption.ENCRYPTED_PREFIX); 55 | } else { 56 | return lastSegment != null && lastSegment.toLowerCase().endsWith(Encryption.ENCRYPTED_SUFFIX); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/loader/CipherModelLoaderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.loader; 20 | 21 | import android.content.Context; 22 | import android.net.Uri; 23 | 24 | import androidx.annotation.NonNull; 25 | 26 | import com.bumptech.glide.load.model.ModelLoader; 27 | import com.bumptech.glide.load.model.ModelLoaderFactory; 28 | import com.bumptech.glide.load.model.MultiModelLoaderFactory; 29 | 30 | import java.io.InputStream; 31 | 32 | public class CipherModelLoaderFactory implements ModelLoaderFactory { 33 | private final Context context; 34 | private final int version; 35 | 36 | public CipherModelLoaderFactory(@NonNull Context context, int version) { 37 | this.context = context.getApplicationContext(); 38 | this.version = version; 39 | } 40 | 41 | @NonNull 42 | @Override 43 | public ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) { 44 | return new CipherModelLoader(context, version); 45 | } 46 | 47 | @Override 48 | public void teardown() { 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/loader/MyAppGlideModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.loader; 20 | 21 | import android.content.Context; 22 | import android.net.Uri; 23 | import android.util.Log; 24 | 25 | import androidx.annotation.NonNull; 26 | 27 | import com.bumptech.glide.Glide; 28 | import com.bumptech.glide.GlideBuilder; 29 | import com.bumptech.glide.Registry; 30 | import com.bumptech.glide.annotation.GlideModule; 31 | import com.bumptech.glide.module.AppGlideModule; 32 | 33 | import java.io.InputStream; 34 | 35 | @GlideModule 36 | public class MyAppGlideModule extends AppGlideModule { 37 | 38 | @Override 39 | public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { 40 | registry.prepend(Uri.class, InputStream.class, new CipherModelLoaderFactory(context, 1)); 41 | registry.prepend(Uri.class, InputStream.class, new CipherModelLoaderFactory(context, 2)); 42 | } 43 | 44 | @Override 45 | public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) { 46 | builder.setLogLevel(Log.ERROR); 47 | super.applyOptions(context, builder); 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/subsampling/ImageViewState.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault.subsampling; 2 | 3 | import android.graphics.PointF; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * Wraps the scale, center and orientation of a displayed image for easy restoration on screen rotate. 11 | */ 12 | public class ImageViewState implements Serializable { 13 | 14 | private final float scale; 15 | 16 | private final float centerX; 17 | 18 | private final float centerY; 19 | 20 | private final int orientation; 21 | 22 | public ImageViewState(float scale, @NonNull PointF center, int orientation) { 23 | this.scale = scale; 24 | this.centerX = center.x; 25 | this.centerY = center.y; 26 | this.orientation = orientation; 27 | } 28 | 29 | public float getScale() { 30 | return scale; 31 | } 32 | 33 | @NonNull 34 | public PointF getCenter() { 35 | return new PointF(centerX, centerY); 36 | } 37 | 38 | public int getOrientation() { 39 | return orientation; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/subsampling/decoder/CompatDecoderFactory.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault.subsampling.decoder; 2 | 3 | import android.graphics.Bitmap; 4 | import androidx.annotation.NonNull; 5 | 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | /** 10 | * Compatibility factory to instantiate decoders with empty public constructors. 11 | * @param The base type of the decoder this factory will produce. 12 | */ 13 | @SuppressWarnings("WeakerAccess") 14 | public class CompatDecoderFactory implements DecoderFactory { 15 | 16 | private final Class clazz; 17 | private final Bitmap.Config bitmapConfig; 18 | 19 | /** 20 | * Construct a factory for the given class. This must have a default constructor. 21 | * @param clazz a class that implements {@link ImageDecoder} or {@link com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder}. 22 | */ 23 | public CompatDecoderFactory(@NonNull Class clazz) { 24 | this(clazz, null); 25 | } 26 | 27 | /** 28 | * Construct a factory for the given class. This must have a constructor that accepts a {@link Bitmap.Config} instance. 29 | * @param clazz a class that implements {@link ImageDecoder} or {@link ImageRegionDecoder}. 30 | * @param bitmapConfig bitmap configuration to be used when loading images. 31 | */ 32 | public CompatDecoderFactory(@NonNull Class clazz, Bitmap.Config bitmapConfig) { 33 | this.clazz = clazz; 34 | this.bitmapConfig = bitmapConfig; 35 | } 36 | 37 | @Override 38 | @NonNull 39 | public T make() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { 40 | if (bitmapConfig == null) { 41 | return clazz.newInstance(); 42 | } else { 43 | Constructor ctor = clazz.getConstructor(Bitmap.Config.class); 44 | return ctor.newInstance(bitmapConfig); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/subsampling/decoder/DecoderFactory.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault.subsampling.decoder; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | 7 | /** 8 | * Interface for {@link ImageDecoder} and {@link ImageRegionDecoder} factories. 9 | * @param the class of decoder that will be produced. 10 | */ 11 | public interface DecoderFactory { 12 | 13 | /** 14 | * Produce a new instance of a decoder with type {@link T}. 15 | * @return a new instance of your decoder. 16 | * @throws IllegalAccessException if the factory class cannot be instantiated. 17 | * @throws InstantiationException if the factory class cannot be instantiated. 18 | * @throws NoSuchMethodException if the factory class cannot be instantiated. 19 | * @throws InvocationTargetException if the factory class cannot be instantiated. 20 | */ 21 | @NonNull 22 | T make() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException; 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/subsampling/decoder/ImageDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.subsampling.decoder; 19 | 20 | import android.content.Context; 21 | import android.graphics.Bitmap; 22 | import android.net.Uri; 23 | 24 | import androidx.annotation.NonNull; 25 | 26 | /** 27 | * Interface for image decoding classes, allowing the default {@link android.graphics.BitmapFactory} 28 | * based on the Skia library to be replaced with a custom class. 29 | */ 30 | public interface ImageDecoder { 31 | 32 | /** 33 | * Decode an image. The URI can be in one of the following formats: 34 | *
35 | * File: file:///scard/picture.jpg 36 | *
37 | * Asset: file:///android_asset/picture.png 38 | *
39 | * Resource: android.resource://com.example.app/drawable/picture 40 | * 41 | * @param context Application context 42 | * @param uri URI of the image 43 | * @param password 44 | * @param version 45 | * @return the decoded bitmap 46 | * @throws Exception if decoding fails. 47 | */ 48 | @NonNull 49 | Bitmap decode(Context context, @NonNull Uri uri, char[] password, int version) throws Exception; 50 | 51 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/subsampling/decoder/ImageRegionDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.subsampling.decoder; 19 | 20 | import android.content.Context; 21 | import android.graphics.Bitmap; 22 | import android.graphics.Point; 23 | import android.graphics.Rect; 24 | import android.net.Uri; 25 | 26 | import androidx.annotation.NonNull; 27 | 28 | /** 29 | * Interface for image decoding classes, allowing the default {@link android.graphics.BitmapRegionDecoder} 30 | * based on the Skia library to be replaced with a custom class. 31 | */ 32 | public interface ImageRegionDecoder { 33 | 34 | /** 35 | * Initialise the decoder. When possible, perform initial setup work once in this method. The 36 | * dimensions of the image must be returned. The URI can be in one of the following formats: 37 | *
38 | * File: file:///scard/picture.jpg 39 | *
40 | * Asset: file:///android_asset/picture.png 41 | *
42 | * Resource: android.resource://com.example.app/drawable/picture 43 | * 44 | * @param context Application context. A reference may be held, but must be cleared on recycle. 45 | * @param uri URI of the image. 46 | * @param password 47 | * @param version 48 | * @return Dimensions of the image. 49 | * @throws Exception if initialisation fails. 50 | */ 51 | @NonNull 52 | Point init(Context context, @NonNull Uri uri, char[] password, int version) throws Exception; 53 | 54 | /** 55 | *

56 | * Decode a region of the image with the given sample size. This method is called off the UI 57 | * thread so it can safely load the image on the current thread. It is called from 58 | * {@link android.os.AsyncTask}s running in an executor that may have multiple threads, so 59 | * implementations must be thread safe. Adding synchronized to the method signature 60 | * is the simplest way to achieve this, but bear in mind the {@link #recycle()} method can be 61 | * called concurrently. 62 | *

63 | * See {@link SkiaImageRegionDecoder} and {@link SkiaPooledImageRegionDecoder} for examples of 64 | * internal locking and synchronization. 65 | *

66 | * 67 | * @param sRect Source image rectangle to decode. 68 | * @param sampleSize Sample size. 69 | * @return The decoded region. It is safe to return null if decoding fails. 70 | */ 71 | @NonNull 72 | Bitmap decodeRegion(@NonNull Rect sRect, int sampleSize); 73 | 74 | /** 75 | * Status check. Should return false before initialisation and after recycle. 76 | * 77 | * @return true if the decoder is ready to be used. 78 | */ 79 | boolean isReady(); 80 | 81 | /** 82 | * This method will be called when the decoder is no longer required. It should clean up any resources still in use. 83 | */ 84 | void recycle(); 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/subsampling/decoder/SkiaImageDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.subsampling.decoder; 19 | 20 | import android.content.ContentResolver; 21 | import android.content.Context; 22 | import android.graphics.Bitmap; 23 | import android.graphics.BitmapFactory; 24 | import android.net.Uri; 25 | 26 | import androidx.annotation.Keep; 27 | import androidx.annotation.NonNull; 28 | import androidx.annotation.Nullable; 29 | 30 | import se.arctosoft.vault.encryption.Encryption; 31 | import se.arctosoft.vault.subsampling.MySubsamplingScaleImageView; 32 | 33 | /** 34 | * Default implementation of {@link com.davemorrissey.labs.subscaleview.decoder.ImageDecoder} 35 | * using Android's {@link android.graphics.BitmapFactory}, based on the Skia library. This 36 | * works well in most circumstances and has reasonable performance, however it has some problems 37 | * with grayscale, indexed and CMYK images. 38 | */ 39 | public class SkiaImageDecoder implements ImageDecoder { 40 | private final Bitmap.Config bitmapConfig; 41 | 42 | @Keep 43 | @SuppressWarnings("unused") 44 | public SkiaImageDecoder() { 45 | this(null); 46 | } 47 | 48 | @SuppressWarnings({"WeakerAccess", "SameParameterValue"}) 49 | public SkiaImageDecoder(@Nullable Bitmap.Config bitmapConfig) { 50 | Bitmap.Config globalBitmapConfig = MySubsamplingScaleImageView.getPreferredBitmapConfig(); 51 | if (bitmapConfig != null) { 52 | this.bitmapConfig = bitmapConfig; 53 | } else if (globalBitmapConfig != null) { 54 | this.bitmapConfig = globalBitmapConfig; 55 | } else { 56 | this.bitmapConfig = Bitmap.Config.RGB_565; 57 | } 58 | } 59 | 60 | @Override 61 | @NonNull 62 | public Bitmap decode(Context context, @NonNull Uri uri, char[] password, int version) throws Exception { 63 | BitmapFactory.Options options = new BitmapFactory.Options(); 64 | Bitmap bitmap; 65 | options.inPreferredConfig = bitmapConfig; 66 | Encryption.Streams streams = null; 67 | try { 68 | ContentResolver contentResolver = context.getContentResolver(); 69 | streams = Encryption.getCipherInputStream(contentResolver.openInputStream(uri), password, false, version); 70 | bitmap = BitmapFactory.decodeStream(streams.getInputStream(), null, options); 71 | } finally { 72 | if (streams != null) { 73 | streams.close(); 74 | } 75 | } 76 | if (bitmap == null) { 77 | throw new RuntimeException("Skia image region decoder returned null bitmap - image format may not be supported"); 78 | } 79 | return bitmap; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/utils/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.utils; 20 | 21 | public class Constants { 22 | public static final float FULL = 1f; 23 | public static final float HALF = 0.5f; 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/utils/GlideStuff.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.utils; 20 | 21 | import androidx.annotation.NonNull; 22 | 23 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 24 | import com.bumptech.glide.request.RequestOptions; 25 | import com.bumptech.glide.signature.ObjectKey; 26 | 27 | import se.arctosoft.vault.MainActivity; 28 | 29 | public class GlideStuff { 30 | 31 | @NonNull 32 | public static RequestOptions getRequestOptions(boolean useDiskCache) { 33 | return new RequestOptions() 34 | .diskCacheStrategy(useDiskCache ? DiskCacheStrategy.AUTOMATIC : DiskCacheStrategy.NONE) 35 | .signature(new ObjectKey(MainActivity.GLIDE_KEY)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/utils/Pixels.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (c) 2024 Arctosoft AB. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. 16 | */ 17 | 18 | package se.arctosoft.vault.utils; 19 | 20 | import android.content.Context; 21 | import android.util.DisplayMetrics; 22 | 23 | import androidx.annotation.NonNull; 24 | 25 | public class Pixels { 26 | 27 | public static int dpToPixel(float dp, @NonNull Context context) { 28 | return (int) (dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/utils/StringStuff.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.utils; 20 | 21 | import android.icu.text.DecimalFormat; 22 | 23 | import androidx.annotation.NonNull; 24 | 25 | import java.util.Random; 26 | 27 | public class StringStuff { 28 | private static final String ALLOWED_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 29 | private static final int NAME_LENGTH = 32; 30 | 31 | public static String getRandomFileName() { 32 | return getRandomFileName(NAME_LENGTH); 33 | } 34 | 35 | @NonNull 36 | public static String getRandomFileName(int length) { 37 | final Random random = new Random(); 38 | final StringBuilder sb = new StringBuilder(length); 39 | for (int i = 0; i < length; ++i) { 40 | sb.append(ALLOWED_CHARACTERS.charAt(random.nextInt(ALLOWED_CHARACTERS.length()))); 41 | } 42 | return sb.toString(); 43 | } 44 | 45 | public static String bytesToReadableString(long bytes) { 46 | final DecimalFormat decimalFormat = new DecimalFormat("0.00"); 47 | if (bytes < 1000) { 48 | return decimalFormat.format(bytes + 0.0) + " B"; 49 | } else if (bytes < 1000000) { 50 | return decimalFormat.format(bytes / 1000.0) + " kB"; 51 | } else { 52 | return decimalFormat.format(bytes / 1000000.0) + " MB"; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/utils/Toaster.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.utils; 20 | 21 | import android.content.Context; 22 | import android.widget.Toast; 23 | 24 | import androidx.annotation.NonNull; 25 | 26 | import java.lang.ref.WeakReference; 27 | 28 | public class Toaster { 29 | private static Toaster toaster; 30 | private static Toast toast; 31 | private final WeakReference weakReference; 32 | 33 | private Toaster(@NonNull Context context) { 34 | weakReference = new WeakReference<>(context); 35 | } 36 | 37 | public static Toaster getInstance(@NonNull Context context) { 38 | if (toaster == null) { 39 | toaster = new Toaster(context.getApplicationContext()); 40 | } 41 | return toaster; 42 | } 43 | 44 | public void showShort(@NonNull String message) { 45 | show(message, Toast.LENGTH_SHORT); 46 | } 47 | 48 | public void showLong(@NonNull String message) { 49 | show(message, Toast.LENGTH_LONG); 50 | } 51 | 52 | private void show(@NonNull String message, int duration) { 53 | if (toast != null) { 54 | toast.cancel(); 55 | } 56 | toast = Toast.makeText(weakReference.get(), message, duration); 57 | toast.show(); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/viewmodel/PasswordViewModel.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault.viewmodel; 2 | 3 | import androidx.lifecycle.ViewModel; 4 | 5 | import se.arctosoft.vault.data.Password; 6 | 7 | public class PasswordViewModel extends ViewModel { 8 | private static final String TAG = "PasswordViewModel"; 9 | 10 | private Password password; 11 | 12 | public boolean isLocked() { 13 | initPassword(); 14 | return password.getPassword() == null; 15 | } 16 | 17 | private void initPassword() { 18 | if (password == null) { 19 | this.password = Password.getInstance(); 20 | } 21 | } 22 | 23 | public void setPassword(char[] password) { 24 | initPassword(); 25 | this.password.setPassword(password); 26 | } 27 | 28 | public char[] getPassword() { 29 | initPassword(); 30 | return password.getPassword(); 31 | } 32 | 33 | public void clearPassword() { 34 | if (password != null) { 35 | password.clearPassword(); 36 | password = null; 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/viewmodel/ShareViewModel.java: -------------------------------------------------------------------------------- 1 | package se.arctosoft.vault.viewmodel; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.documentfile.provider.DocumentFile; 5 | import androidx.lifecycle.MutableLiveData; 6 | import androidx.lifecycle.ViewModel; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class ShareViewModel extends ViewModel { 12 | private static final String TAG = "ShareViewModel"; 13 | 14 | private MutableLiveData hasData; 15 | private final List filesReceived = new ArrayList<>(); 16 | 17 | public void setHasData(boolean hasData) { 18 | if (this.hasData == null) { 19 | this.hasData = new MutableLiveData<>(hasData); 20 | } else { 21 | this.hasData.setValue(hasData); 22 | } 23 | } 24 | 25 | @NonNull 26 | public MutableLiveData getHasData() { 27 | if (this.hasData == null) { 28 | this.hasData = new MutableLiveData<>(false); 29 | } 30 | return hasData; 31 | } 32 | 33 | public List getFilesReceived() { 34 | return filesReceived; 35 | } 36 | 37 | public void clear() { 38 | setHasData(false); 39 | filesReceived.clear(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/views/GridImageView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.views; 20 | 21 | import android.content.Context; 22 | import android.util.AttributeSet; 23 | 24 | import androidx.appcompat.widget.AppCompatImageView; 25 | 26 | public class GridImageView extends AppCompatImageView { 27 | 28 | public GridImageView(Context context) { 29 | super(context); 30 | } 31 | 32 | public GridImageView(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | } 35 | 36 | public GridImageView(Context context, AttributeSet attrs, int defStyleAttr) { 37 | super(context, attrs, defStyleAttr); 38 | } 39 | 40 | @Override 41 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 42 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 43 | 44 | int width = getMeasuredWidth(); 45 | setMeasuredDimension(width, (int) (width * 1.2)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/views/PressableConstraintLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.views; 20 | 21 | import android.content.Context; 22 | import android.util.AttributeSet; 23 | 24 | import androidx.constraintlayout.widget.ConstraintLayout; 25 | 26 | import se.arctosoft.vault.utils.Constants; 27 | 28 | public class PressableConstraintLayout extends ConstraintLayout { 29 | 30 | public PressableConstraintLayout(Context context) { 31 | super(context); 32 | } 33 | 34 | public PressableConstraintLayout(Context context, AttributeSet attrs) { 35 | super(context, attrs); 36 | } 37 | 38 | public PressableConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) { 39 | super(context, attrs, defStyleAttr); 40 | } 41 | 42 | @Override 43 | public void setPressed(boolean pressed) { 44 | super.setPressed(pressed); 45 | setAlpha(pressed ? Constants.HALF : Constants.FULL); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/views/PressableGridTextView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.views; 20 | 21 | import android.content.Context; 22 | import android.util.AttributeSet; 23 | 24 | public class PressableGridTextView extends androidx.appcompat.widget.AppCompatTextView { 25 | 26 | public PressableGridTextView(Context context) { 27 | super(context); 28 | } 29 | 30 | public PressableGridTextView(Context context, AttributeSet attrs) { 31 | super(context, attrs); 32 | } 33 | 34 | public PressableGridTextView(Context context, AttributeSet attrs, int defStyleAttr) { 35 | super(context, attrs, defStyleAttr); 36 | } 37 | 38 | @Override 39 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 40 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 41 | 42 | int width = getMeasuredWidth(); 43 | setMeasuredDimension(width, (int) (width * 1.2)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/views/PressableImageView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.views; 20 | 21 | import android.content.Context; 22 | import android.util.AttributeSet; 23 | 24 | import androidx.appcompat.widget.AppCompatImageView; 25 | 26 | import se.arctosoft.vault.utils.Constants; 27 | 28 | public class PressableImageView extends AppCompatImageView { 29 | 30 | public PressableImageView(Context context) { 31 | super(context); 32 | } 33 | 34 | public PressableImageView(Context context, AttributeSet attrs) { 35 | super(context, attrs); 36 | } 37 | 38 | public PressableImageView(Context context, AttributeSet attrs, int defStyleAttr) { 39 | super(context, attrs, defStyleAttr); 40 | } 41 | 42 | @Override 43 | public void setPressed(boolean pressed) { 44 | super.setPressed(pressed); 45 | setAlpha(pressed ? Constants.HALF : Constants.FULL); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/se/arctosoft/vault/views/PressableRelativeLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Valv-Android 3 | * Copyright (C) 2024 Arctosoft AB 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see https://www.gnu.org/licenses/. 17 | */ 18 | 19 | package se.arctosoft.vault.views; 20 | 21 | import android.content.Context; 22 | import android.util.AttributeSet; 23 | import android.widget.RelativeLayout; 24 | 25 | import se.arctosoft.vault.utils.Constants; 26 | 27 | public class PressableRelativeLayout extends RelativeLayout { 28 | 29 | public PressableRelativeLayout(Context context) { 30 | super(context); 31 | } 32 | 33 | public PressableRelativeLayout(Context context, AttributeSet attrs) { 34 | super(context, attrs); 35 | } 36 | 37 | public PressableRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | } 40 | 41 | @Override 42 | public void setPressed(boolean pressed) { 43 | super.setPressed(pressed); 44 | setAlpha(pressed ? Constants.HALF : Constants.FULL); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_folder_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_play_arrow_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_select_all_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_create_new_folder_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_delete_forever_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_file_download_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_image_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_library_add_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_lock_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_tips_and_updates_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_video_file_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_folder_open_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_fullscreen_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_gif_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_lock_open_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_remove_circle_outline_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_round_view_compact_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/drawable/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_add_photo_alternate_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_broken_image_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_drive_file_move_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_file_copy_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_hide_image_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_sd_storage_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/outline_text_snippet_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_add_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_all_inclusive_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_edit_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_expand_less_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_expand_more_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_filter_list_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_key_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_more_vert_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_sort_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 21 | 22 | 23 | 24 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_gallery_grid_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | 37 | 38 | 49 | 50 | 51 | 52 | 60 | 61 | 70 | 71 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_gallery_viewpager_item_directory.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 26 | 27 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_gallery_viewpager_item_gif.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_gallery_viewpager_item_image.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_gallery_viewpager_item_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 15 | 16 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_gallery_viewpager_item_video.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 21 | 22 | 28 | 29 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_import_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_edit_note.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 30 | 31 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_import.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | 26 | 31 | 32 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_import_text.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 30 | 31 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_set_iteration_count.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 25 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/image_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/loading_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | 27 | 28 | 38 | 39 | 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_dir.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 16 | 17 | 20 | 23 | 26 | 29 | 32 | 33 | 34 | 39 | 40 | 43 | 46 | 49 | 52 | 55 | 56 | 57 | 62 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_gallery_viewpager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main_selection_dir.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 16 | 21 | 26 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main_selection_root.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_root.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 16 | 17 | 20 | 23 | 26 | 29 | 32 | 33 | 34 | 38 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_v.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_v_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-hdpi/ic_launcher_v.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_v_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-hdpi/ic_launcher_v_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_v_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-hdpi/ic_launcher_v_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_v_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-hdpi/ic_launcher_v_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-mdpi/ic_launcher_v.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_v_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-mdpi/ic_launcher_v_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_v_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-mdpi/ic_launcher_v_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_v_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-mdpi/ic_launcher_v_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xhdpi/ic_launcher_v.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_v_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xhdpi/ic_launcher_v_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_v_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xhdpi/ic_launcher_v_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_v_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xhdpi/ic_launcher_v_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxhdpi/ic_launcher_v.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_v_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxhdpi/ic_launcher_v_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_v_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxhdpi/ic_launcher_v_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_v_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxhdpi/ic_launcher_v_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_v_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_v_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_v_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Arctosoft/Valv-Android/e4aafe8fe21b85e21a4e7045c537741fdb41f28f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_v_round.png -------------------------------------------------------------------------------- /app/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 16 | 19 | 23 | 27 | 28 | 31 | 32 | 33 | 38 | 41 | 42 | 43 | 48 | 49 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/bool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 26 | 27 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/values-w1240dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 200dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-w600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reply 5 | Reply to all 6 | 7 | 8 | 9 | reply 10 | reply_all 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/values/bool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF000000 4 | #FFFFFFFF 5 | #99FFFFFF 6 | #99000000 7 | #EBFFFFFF 8 | #BF000000 9 | #1A000000 10 | #B3000000 11 | #1AFFFFFF 12 | #DF454545 13 | #DFE8E8E8 14 | #0CFFFFFF 15 | #0D000000 16 | #03a9f4 17 | #007ac1 18 | #0793D3 19 | #1D76AA 20 | #3EBACA 21 | #209AAA 22 | #13A2B5 23 | #178493 24 | #CA1818 25 | 26 | #FBFBFB 27 | #00FFFFFF 28 | #F6DB41 29 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | 16dp 5 | 16dp 6 | 0dp 7 | 5dp 8 | 28dp 9 | 12dp 10 | 18sp 11 | 12dp 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | 28 | 31 | 32 |