Compare commits
	
		
			96 Commits
		
	
	
		
			1.0-rc8
			...
			96904bce79
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 96904bce79 | ||
|  | 08675a5fc3 | ||
|  | 019046474c | ||
|  | 0e63b6a50d | ||
|  | 608ff610d8 | ||
| a009ce0c15 | |||
|  | 1ba95c54a2 | ||
|  | 51987f54e1 | ||
|  | efb3a436c4 | ||
|  | 8a22d3b66e | ||
|  | c404d498d5 | ||
|  | 10d35956b3 | ||
|  | 1de639dc46 | ||
|  | a297988d33 | ||
|  | e788d064a5 | ||
|  | d6692b5b7c | ||
|  | 5ac4ba1d43 | ||
|  | 50573a37c4 | ||
|  | 2528b7df5d | ||
|  | e6159f6f42 | ||
|  | f2982be549 | ||
|  | 0c5f7a658f | ||
|  | 9b90057f85 | ||
|  | a9192314de | ||
|  | aa08418109 | ||
|  | 5b239ace83 | ||
|  | 555cd8ada2 | ||
|  | b188313eb9 | ||
|  | 74ea62e8cd | ||
|  | a59d79aa0e | ||
|  | e8021f37dd | ||
|  | 4e179d8698 | ||
|  | a91f8545b0 | ||
|  | 94642047fb | ||
|  | e99f615fcd | ||
|  | 3ba61e87f9 | ||
|  | b798200883 | ||
|  | 2998362518 | ||
|  | 73e3add4a8 | ||
|  | 5b43db3ebd | ||
|  | f9535fe2da | ||
|  | aa20ec5a06 | ||
|  | 917a01b2ed | ||
|  | e7f55c2be2 | ||
|  | eb765e09e7 | ||
|  | 1cf4a6bc36 | ||
|  | 7f0212fc5d | ||
|  | 413d8bd7bf | ||
|  | 931adbb4dd | ||
|  | e6b2dfe37a | ||
|  | f73f9b5acf | ||
|  | ba2d0ac024 | ||
|  | f33b4672b0 | ||
|  | b6b69587fa | ||
| 06a006c0a2 | |||
|  | 8ae38f4250 | ||
|  | 3e1252cc0a | ||
|  | e4357a66e0 | ||
|  | 21f2c0d69f | ||
|  | 340789989c | ||
|  | 2428f4e50b | ||
| f4c9eddd22 | |||
|  | 6a5e971619 | ||
|  | 5829f18908 | ||
|  | 426d94ba81 | ||
| a58d208d49 | |||
|  | 069edaf6a2 | ||
| d0aa2fbeb9 | |||
| 17c75f27bc | |||
|  | 1738664f83 | ||
|  | a5b55fe214 | ||
| 0cd90413d1 | |||
|  | 653ee1ccc1 | ||
|  | 9b6a69e227 | ||
|  | e40305b680 | ||
|  | 668e9d653f | ||
| bcfcb85121 | |||
| 49c650c8a9 | |||
|  | b5f52c7e13 | ||
|  | d81922d2c9 | ||
| 84b2c2c455 | |||
| 841c3dea24 | |||
|  | 6596f347a1 | ||
|  | a2dd009533 | ||
|  | 4104104b16 | ||
|  | 0d838b6209 | ||
|  | 1d41671fb6 | ||
|  | 84ebdcc9a8 | ||
|  | 8181da421e | ||
|  | af97381bdb | ||
|  | ba94beab37 | ||
| 19b0f91852 | |||
|  | 3b0bf2097e | ||
| 455c95021b | |||
|  | 78ad7f983f | ||
|  | 0a0b55294f | 
							
								
								
									
										
											BIN
										
									
								
								.github/images/apk.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								.github/images/izzy.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 20 KiB | 
							
								
								
									
										10
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,3 +1,4 @@ | |||||||
|  | #file: noinspection SpellCheckingInspection | ||||||
|  |  | ||||||
| name: CI-Android APK | name: CI-Android APK | ||||||
|  |  | ||||||
| @@ -7,11 +8,11 @@ env: | |||||||
|  |  | ||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: [ release ] |     branches: [ main ] | ||||||
|     tags: |     tags: | ||||||
|       - '**' |       - '**' | ||||||
|   pull_request: |   pull_request: | ||||||
|     branches: [ release ] |     branches: [ main ] | ||||||
|   workflow_dispatch: |   workflow_dispatch: | ||||||
|  |  | ||||||
| # A workflow run is made up of one or more jobs that can run sequentially or in parallel | # A workflow run is made up of one or more jobs that can run sequentially or in parallel | ||||||
| @@ -27,11 +28,11 @@ jobs: | |||||||
|       - name: set up secrets |       - name: set up secrets | ||||||
|         run: | |         run: | | ||||||
|           echo "${{ secrets.RELEASE_KEYSTORE }}" > keystore.asc |           echo "${{ secrets.RELEASE_KEYSTORE }}" > keystore.asc | ||||||
|           echo "${{ secrets.RELEASE_KEY}}" > key.acs |           echo "${{ secrets.RELEASE_KEY}}" > key.asc | ||||||
|           gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch keystore.asc > app/keystore.properties |           gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch keystore.asc > app/keystore.properties | ||||||
|           gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch key.asc > app/key.jks |           gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch key.asc > app/key.jks | ||||||
|  |  | ||||||
|       - uses: gradle/wrapper-validation-action@v2 |       - uses: gradle/wrapper-validation-action@v3 | ||||||
|  |  | ||||||
|       - name: create and checkout branch |       - name: create and checkout branch | ||||||
|         if: github.event_name == 'pull_request' |         if: github.event_name == 'pull_request' | ||||||
| @@ -57,6 +58,7 @@ jobs: | |||||||
|  |  | ||||||
|       - name: Release |       - name: Release | ||||||
|         uses: softprops/action-gh-release@v2 |         uses: softprops/action-gh-release@v2 | ||||||
|  |         if: startsWith(github.ref, 'refs/tags/') | ||||||
|         with: |         with: | ||||||
|           files: | |           files: | | ||||||
|             app/build/outputs/apk/release/app-release.apk |             app/build/outputs/apk/release/app-release.apk | ||||||
							
								
								
									
										24
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,24 @@ | |||||||
|  | This is free and unencumbered software released into the public domain. | ||||||
|  |  | ||||||
|  | Anyone is free to copy, modify, publish, use, compile, sell, or | ||||||
|  | distribute this software, either in source code form or as a compiled | ||||||
|  | binary, for any purpose, commercial or non-commercial, and by any | ||||||
|  | means. | ||||||
|  |  | ||||||
|  | In jurisdictions that recognize copyright laws, the author or authors | ||||||
|  | of this software dedicate any and all copyright interest in the | ||||||
|  | software to the public domain. We make this dedication for the benefit | ||||||
|  | of the public at large and to the detriment of our heirs and | ||||||
|  | successors. We intend this dedication to be an overt act of | ||||||
|  | relinquishment in perpetuity of all present and future rights to this | ||||||
|  | software under copyright law. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||||
|  | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||||
|  | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||||
|  | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  | OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  | ||||||
|  | For more information, please refer to <https://unlicense.org> | ||||||
							
								
								
									
										73
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -0,0 +1,73 @@ | |||||||
|  | <!--suppress ALL --> | ||||||
|  | <div align="center"> | ||||||
|  |   <h1>Keepass Fidelity</h1> | ||||||
|  |   <img width="100px" src="./metadata/en-US/images/icon.png" alt="Logo"> | ||||||
|  |    | ||||||
|  |   <p>A minimalist fidelity/loyalty card plugin</p> | ||||||
|  |    | ||||||
|  |   <img src="https://forthebadge.com/images/badges/built-for-android.svg" alt="Built for Android"> | ||||||
|  |   <img src="https://forthebadge.com/images/badges/built-with-love.svg" alt="Built with love"> | ||||||
|  |   <br> | ||||||
|  |     <a href="https://github.com/choelzl/keepass-fidelity/actions/workflows/build.yml"> | ||||||
|  |     <img src="https://github.com/choelzl/keepass-fidelity/actions/workflows/build.yml/badge.svg?branch=main" alt="Build Status"> | ||||||
|  |   </a> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | ## 🌄 Screenshots | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <table> | ||||||
|  |     <tr> | ||||||
|  |       <td style="width: 33%; height: 100px;"><img src="./metadata/en-US/images/phoneScreenshots/launcher.jpg" alt="Launcher" style="width: 100%; height: 100%;"></td> | ||||||
|  |       <td style="width: 33%; height: 100px;"><img src="./metadata/en-US/images/phoneScreenshots/view.jpg" alt="View" style="width: 100%; height: 100%;"></td> | ||||||
|  |       <td style="width: 33%; height: 100px;"><img src="./metadata/en-US/images/phoneScreenshots/edit.jpg" alt="Edit" style="width: 100%; height: 100%;"></td> | ||||||
|  |     </tr> | ||||||
|  |   </table> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | ## ⭐ Features | ||||||
|  |  | ||||||
|  | - Search entries in [Keepass2Android](https://github.com/PhilippC/keepass2android/) | ||||||
|  | - Scan & Create entries | ||||||
|  | - Recently used history for fast access | ||||||
|  | - Protect entries from caching | ||||||
|  | - Minimalist design and features | ||||||
|  | - Supported Formats: CODE_39, CODE_93, CODE_128, EAN_8, EAN_13, UPC_A, UPC_E, CODE_QR, PDF_417, AZTEC, CODABAR, DATA_MATRIX, ITF | ||||||
|  |  | ||||||
|  | ## 📳 Installation | ||||||
|  |  | ||||||
|  | <div style="display: flex; justify-content: center; align-items: center; flex-direction: row;"> | ||||||
|  |     <a href="https://apt.izzysoft.de/fdroid/index/apk/net.helcel.fidelity"> | ||||||
|  |         <img width="200" height="80" alt="Izzy Download" src=".github/images/izzy.png"> | ||||||
|  |     </a> | ||||||
|  |     <a href="https://github.com/choelzl/keepass-fidelity/releases/latest"> | ||||||
|  |         <img width="200" height="84" alt="APK Download" src=".github/images/apk.png"> | ||||||
|  |     </a> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | ## ⚙️ Permissions | ||||||
|  |  | ||||||
|  | - `CAMERA`: necessary for importing barcodes from camera | ||||||
|  | - `READ_MEDIA_VISUAL_USER_SELECTED`: necessary for the importing barcode from images | ||||||
|  |  | ||||||
|  | ## 📝 Contribute | ||||||
|  |  | ||||||
|  | Keepass-Fidelity is a user-driven project. We welcome any contribution, big or small. | ||||||
|  |  | ||||||
|  | - **🖥️ Development:** Fix bugs, implement features, or research issues. Open a PR for review. | ||||||
|  | - **🍥 Design:** Improve interfaces, including accessibility and usability. | ||||||
|  | - **📂 Issue Reporting:** Report bugs and edge cases with relevant info. | ||||||
|  | - **🌍 Localization:** Translate if it doesn't support your language. | ||||||
|  |  | ||||||
|  | ## ✏️ Acknowledgements | ||||||
|  |  | ||||||
|  | Thanks to all contributors, the developers of our dependencies, and our users. | ||||||
|  |  | ||||||
|  | ## 📝 License | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | Copyright (C) 2024 Helcel | ||||||
|  |  | ||||||
|  | Licensed under the Unlicense | ||||||
|  | For more information, please refer to <https://unlicense.org> | ||||||
|  | ``` | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| plugins { | plugins { | ||||||
|     id 'com.android.application' |     id 'com.android.application' | ||||||
|     id 'org.jetbrains.kotlin.android' |     id 'org.jetbrains.kotlin.android' | ||||||
|     id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.23' |     id 'org.jetbrains.kotlin.plugin.serialization' version '2.0.21' | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -19,8 +19,6 @@ android { | |||||||
|         resValue "string", "app_name", "Keepass Fidelity" |         resValue "string", "app_name", "Keepass Fidelity" | ||||||
|         minSdk 28 |         minSdk 28 | ||||||
|         targetSdk 34 |         targetSdk 34 | ||||||
|         versionCode 1 |  | ||||||
|         versionName "1.0" |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -36,6 +34,7 @@ android { | |||||||
|     buildTypes { |     buildTypes { | ||||||
|         debug { |         debug { | ||||||
|             debuggable true |             debuggable true | ||||||
|  |             signingConfig = signingConfigs.getByName("release") | ||||||
|         } |         } | ||||||
|         release { |         release { | ||||||
|             minifyEnabled true |             minifyEnabled true | ||||||
| @@ -61,22 +60,25 @@ android { | |||||||
|     buildFeatures { |     buildFeatures { | ||||||
|         viewBinding true |         viewBinding true | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     dependenciesInfo { | ||||||
|  |         // Disables dependency metadata when building APKs. | ||||||
|  |         includeInApk = false | ||||||
|  |         // Disables dependency metadata when building Android App Bundles. | ||||||
|  |         includeInBundle = false | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
|  |     coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.3' | ||||||
|  |  | ||||||
|     coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.4' |     implementation 'androidx.camera:camera-lifecycle:1.4.0' | ||||||
|     implementation 'androidx.appcompat:appcompat:1.6.1' |     implementation 'androidx.camera:camera-view:1.4.0' | ||||||
|     implementation 'androidx.core:core-ktx:1.12.0' |     runtimeOnly 'androidx.camera:camera-camera2:1.4.0' | ||||||
|     implementation 'androidx.preference:preference-ktx:1.2.1' |  | ||||||
|     implementation 'androidx.constraintlayout:constraintlayout:2.1.4' |     implementation 'com.google.code.gson:gson:2.11.0' | ||||||
|     implementation 'androidx.camera:camera-camera2:1.3.2' |     implementation 'com.google.android.material:material:1.12.0' | ||||||
|     implementation 'androidx.camera:camera-lifecycle:1.3.2' |  | ||||||
|     implementation 'androidx.camera:camera-view:1.3.2' |  | ||||||
|     implementation 'com.google.code.gson:gson:2.10.1' |  | ||||||
|     implementation 'com.google.android.material:material:1.11.0' |  | ||||||
|     implementation 'com.google.zxing:core:3.5.3' |     implementation 'com.google.zxing:core:3.5.3' | ||||||
|     implementation 'com.google.mlkit:barcode-scanning:17.2.0' |  | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -1,13 +1,16 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|     xmlns:tools="http://schemas.android.com/tools" |     xmlns:tools="http://schemas.android.com/tools" | ||||||
|     android:versionCode="1" |     android:versionCode="8" | ||||||
|     android:versionName="1.0"> |     android:versionName="1.2c"> | ||||||
|  |  | ||||||
|     <uses-feature android:name="android.hardware.camera" /> |     <uses-feature android:name="android.hardware.camera" /> | ||||||
|  |  | ||||||
|     <uses-permission android:name="android.permission.CAMERA" /> |     <uses-permission android:name="android.permission.CAMERA" /> | ||||||
|  |     <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" /> | ||||||
|  |  | ||||||
|     <application |     <application | ||||||
|         android:icon="@drawable/logo" |         android:icon="@mipmap/ic_launcher_round" | ||||||
|         android:label="@string/app_name" |         android:label="@string/app_name" | ||||||
|         android:supportsRtl="true"> |         android:supportsRtl="true"> | ||||||
|         <activity |         <activity | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
| @@ -31,7 +31,6 @@ class MainActivity : AppCompatActivity() { | |||||||
|  |  | ||||||
|         binding = ActMainBinding.inflate(layoutInflater) |         binding = ActMainBinding.inflate(layoutInflater) | ||||||
|         setContentView(binding.root) |         setContentView(binding.root) | ||||||
|  |  | ||||||
|         onBackPressedDispatcher.addCallback(this) { |         onBackPressedDispatcher.addCallback(this) { | ||||||
|             if (supportFragmentManager.backStackEntryCount > 0) { |             if (supportFragmentManager.backStackEntryCount > 0) { | ||||||
|                 supportFragmentManager.popBackStackImmediate() |                 supportFragmentManager.popBackStackImmediate() | ||||||
|   | |||||||
| @@ -156,6 +156,11 @@ class CreateEntry : Fragment() { | |||||||
|             } catch (e: Exception) { |             } catch (e: Exception) { | ||||||
|                 e.printStackTrace() |                 e.printStackTrace() | ||||||
|             } |             } | ||||||
|  |             if (!binding.checkboxProtected.isChecked) { | ||||||
|  |                 val r = KeepassWrapper.entryExtract(kpEntry.first) | ||||||
|  |                 CacheManager.addFidelity(r) | ||||||
|  |             } | ||||||
|  |             activity?.supportFragmentManager?.popBackStack() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,107 @@ | |||||||
|  | package net.helcel.fidelity.activity.fragment | ||||||
|  |  | ||||||
|  | import android.Manifest | ||||||
|  | import android.graphics.BitmapFactory | ||||||
|  | import android.net.Uri | ||||||
|  | import android.os.Build | ||||||
|  | import android.os.Bundle | ||||||
|  | import android.view.LayoutInflater | ||||||
|  | import android.view.View | ||||||
|  | import android.view.ViewGroup | ||||||
|  | import androidx.activity.result.PickVisualMediaRequest | ||||||
|  | import androidx.activity.result.contract.ActivityResultContracts | ||||||
|  | import androidx.fragment.app.Fragment | ||||||
|  | import net.helcel.fidelity.R | ||||||
|  | import net.helcel.fidelity.tools.BarcodeScanner | ||||||
|  | import net.helcel.fidelity.tools.ErrorToaster | ||||||
|  | import net.helcel.fidelity.tools.KeepassWrapper | ||||||
|  | import java.io.FileNotFoundException | ||||||
|  |  | ||||||
|  | class FileScanner : Fragment() { | ||||||
|  |  | ||||||
|  |     private var code: String = "" | ||||||
|  |     private var fmt: String = "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private val resultPermission = | ||||||
|  |         registerForActivityResult(ActivityResultContracts.RequestPermission()) { | ||||||
|  |             resultLauncherOpenMediaPick.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     private val resultLauncherOpenMediaBase = | ||||||
|  |         registerForActivityResult(ActivityResultContracts.GetContent()) { | ||||||
|  |             loadUri(it) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     private val resultLauncherOpenMediaPick = | ||||||
|  |         registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { | ||||||
|  |             loadUri(it) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     override fun onCreateView( | ||||||
|  |         inflater: LayoutInflater, | ||||||
|  |         container: ViewGroup?, | ||||||
|  |         savedInstanceState: Bundle? | ||||||
|  |     ): View { | ||||||
|  |         println(Build.VERSION.SDK_INT) | ||||||
|  |         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { | ||||||
|  |             resultPermission.launch(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED) | ||||||
|  |         } else { | ||||||
|  |             // resultLauncherOpenMediaBase.launch("image/*") | ||||||
|  |             resultLauncherOpenMediaPick.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) | ||||||
|  |         } | ||||||
|  |         return View(context) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun startCreateEntry() { | ||||||
|  |         val createEntryFragment = CreateEntry() | ||||||
|  |         createEntryFragment.arguments = | ||||||
|  |             KeepassWrapper.bundleCreate(null, this.code, this.fmt) | ||||||
|  |         requireActivity().supportFragmentManager.beginTransaction() | ||||||
|  |             .replace(R.id.container, createEntryFragment) | ||||||
|  |             .commit() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun scannerResult(code: String?, format: String?) { | ||||||
|  |         if (!code.isNullOrEmpty() && !format.isNullOrEmpty()) { | ||||||
|  |             this.code = code | ||||||
|  |             this.fmt = format | ||||||
|  |         } | ||||||
|  |         val isDone = this.code.isNotEmpty() && this.fmt.isNotEmpty() | ||||||
|  |         requireActivity().runOnUiThread { | ||||||
|  |             if (isDone) { | ||||||
|  |                 startCreateEntry() | ||||||
|  |             } else { | ||||||
|  |                 parentFragmentManager.popBackStack() | ||||||
|  |                 ErrorToaster.nothingFound(context) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun loadUri(it: Uri?) { | ||||||
|  |         try { | ||||||
|  |             run { | ||||||
|  |                 require(it != null) | ||||||
|  |  | ||||||
|  |                 val file = requireContext().contentResolver.openInputStream(it) | ||||||
|  |                 val image = BitmapFactory.decodeStream(file) | ||||||
|  |                 BarcodeScanner.bitmapUseCase(image) { code, format -> | ||||||
|  |                     scannerResult(code, format) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (e: FileNotFoundException) { | ||||||
|  |             e.printStackTrace() | ||||||
|  |             println(e.message) | ||||||
|  |             println(it) | ||||||
|  |             ErrorToaster.noPermission(context) | ||||||
|  |             parentFragmentManager.popBackStack() | ||||||
|  |         } catch (e: IllegalArgumentException) { | ||||||
|  |             ErrorToaster.nothingFound(context) | ||||||
|  |             parentFragmentManager.popBackStack() | ||||||
|  |         } catch (e: SecurityException) { | ||||||
|  |             ErrorToaster.noPermission(context) | ||||||
|  |             parentFragmentManager.popBackStack() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -49,6 +49,11 @@ class Launcher : Fragment() { | |||||||
|             startScanner() |             startScanner() | ||||||
|             hideMenuAdd() |             hideMenuAdd() | ||||||
|         } |         } | ||||||
|  |         binding.btnOpen.setOnClickListener { | ||||||
|  |             startFileScanner() | ||||||
|  |             hideMenuAdd() | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         binding.btnManual.setOnClickListener { |         binding.btnManual.setOnClickListener { | ||||||
|             startCreateEntry() |             startCreateEntry() | ||||||
| @@ -96,6 +101,10 @@ class Launcher : Fragment() { | |||||||
|         startFragment(Scanner()) |         startFragment(Scanner()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private fun startFileScanner() { | ||||||
|  |         startFragment(FileScanner()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private fun startCreateEntry() { |     private fun startCreateEntry() { | ||||||
|         startFragment(CreateEntry()) |         startFragment(CreateEntry()) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,25 +2,23 @@ package net.helcel.fidelity.activity.fragment | |||||||
|  |  | ||||||
| import android.Manifest | import android.Manifest | ||||||
| import android.content.ContentValues | import android.content.ContentValues | ||||||
| import android.content.pm.PackageManager |  | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import android.util.Log | import android.util.Log | ||||||
| import android.view.LayoutInflater | import android.view.LayoutInflater | ||||||
| import android.view.View | import android.view.View | ||||||
| import android.view.ViewGroup | import android.view.ViewGroup | ||||||
|  | import androidx.activity.result.contract.ActivityResultContracts | ||||||
| import androidx.camera.core.CameraSelector | import androidx.camera.core.CameraSelector | ||||||
| import androidx.camera.core.Preview | import androidx.camera.core.Preview | ||||||
| import androidx.camera.lifecycle.ProcessCameraProvider | import androidx.camera.lifecycle.ProcessCameraProvider | ||||||
| import androidx.core.app.ActivityCompat |  | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
| import androidx.fragment.app.Fragment | import androidx.fragment.app.Fragment | ||||||
| import net.helcel.fidelity.R | import net.helcel.fidelity.R | ||||||
| import net.helcel.fidelity.databinding.FragScannerBinding | import net.helcel.fidelity.databinding.FragScannerBinding | ||||||
| import net.helcel.fidelity.tools.BarcodeScanner.getAnalysisUseCase | import net.helcel.fidelity.tools.BarcodeScanner.analysisUseCase | ||||||
|  | import net.helcel.fidelity.tools.ErrorToaster | ||||||
| import net.helcel.fidelity.tools.KeepassWrapper | import net.helcel.fidelity.tools.KeepassWrapper | ||||||
|  |  | ||||||
| private const val CAMERA_PERMISSION_REQUEST_CODE = 1 |  | ||||||
|  |  | ||||||
| class Scanner : Fragment() { | class Scanner : Fragment() { | ||||||
|  |  | ||||||
|     private lateinit var binding: FragScannerBinding |     private lateinit var binding: FragScannerBinding | ||||||
| @@ -28,6 +26,17 @@ class Scanner : Fragment() { | |||||||
|     private var code: String = "" |     private var code: String = "" | ||||||
|     private var fmt: String = "" |     private var fmt: String = "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private val resultPermissionRequest = | ||||||
|  |         registerForActivityResult(ActivityResultContracts.RequestPermission()) { | ||||||
|  |             if (it) { | ||||||
|  |                 bindCameraUseCases() | ||||||
|  |             } else { | ||||||
|  |                 parentFragmentManager.popBackStack() | ||||||
|  |                 ErrorToaster.noPermission(context) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|     override fun onCreateView( |     override fun onCreateView( | ||||||
|         inflater: LayoutInflater, |         inflater: LayoutInflater, | ||||||
|         container: ViewGroup?, |         container: ViewGroup?, | ||||||
| @@ -37,14 +46,12 @@ class Scanner : Fragment() { | |||||||
|         binding.btnScanDone.setOnClickListener { |         binding.btnScanDone.setOnClickListener { | ||||||
|             startCreateEntry() |             startCreateEntry() | ||||||
|         } |         } | ||||||
|         when (hasCameraPermission()) { |  | ||||||
|             true -> bindCameraUseCases() |  | ||||||
|             else -> requestPermission() |  | ||||||
|         } |  | ||||||
|         binding.btnScanDone.isEnabled = false |         binding.btnScanDone.isEnabled = false | ||||||
|  |         resultPermissionRequest.launch(Manifest.permission.CAMERA) | ||||||
|         return binding.root |         return binding.root | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     private fun startCreateEntry() { |     private fun startCreateEntry() { | ||||||
|         val createEntryFragment = CreateEntry() |         val createEntryFragment = CreateEntry() | ||||||
|         createEntryFragment.arguments = |         createEntryFragment.arguments = | ||||||
| @@ -54,26 +61,16 @@ class Scanner : Fragment() { | |||||||
|             .commit() |             .commit() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun hasCameraPermission() = |  | ||||||
|         ActivityCompat.checkSelfPermission( |  | ||||||
|             requireContext(), |  | ||||||
|             Manifest.permission.CAMERA |  | ||||||
|         ) == PackageManager.PERMISSION_GRANTED |  | ||||||
|  |  | ||||||
|     private fun requestPermission() { |  | ||||||
|         ActivityCompat.requestPermissions( |  | ||||||
|             requireActivity(), |  | ||||||
|             arrayOf(Manifest.permission.CAMERA), |  | ||||||
|             CAMERA_PERMISSION_REQUEST_CODE |  | ||||||
|         ) |  | ||||||
|         ActivityCompat.OnRequestPermissionsResultCallback { c, p, i -> |  | ||||||
|             require(c == CAMERA_PERMISSION_REQUEST_CODE) |  | ||||||
|             require(p.contains(Manifest.permission.CAMERA)) |  | ||||||
|             val el = i[p.indexOf(Manifest.permission.CAMERA)] |  | ||||||
|             if (el != PackageManager.PERMISSION_GRANTED) { |  | ||||||
|                 startCreateEntry() |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|  |     private fun scannerResult(code: String?, format: String?) { | ||||||
|  |         if (!code.isNullOrEmpty() && !format.isNullOrEmpty()) { | ||||||
|  |             this.code = code | ||||||
|  |             this.fmt = format | ||||||
|  |         } | ||||||
|  |         val isDone = this.code.isNotEmpty() && this.fmt.isNotEmpty() | ||||||
|  |         activity?.runOnUiThread { | ||||||
|  |             binding.btnScanDone.isEnabled = isDone | ||||||
|  |             binding.ScanActive.isEnabled = !isDone | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -88,15 +85,8 @@ class Scanner : Fragment() { | |||||||
|                     it.setSurfaceProvider(binding.cameraView.surfaceProvider) |                     it.setSurfaceProvider(binding.cameraView.surfaceProvider) | ||||||
|                 } |                 } | ||||||
|             val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA |             val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA | ||||||
|             val analysisUseCase = getAnalysisUseCase { code, format -> |             val analysisUseCase = analysisUseCase { code, format -> | ||||||
|                 if (code != null && format != null) { |                 scannerResult(code, format) | ||||||
|                     this.code = code |  | ||||||
|                     this.fmt = format |  | ||||||
|                     binding.btnScanDone.isEnabled = true |  | ||||||
|  |  | ||||||
|                 } else { |  | ||||||
|                     binding.btnScanDone.isEnabled = false |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             try { |             try { | ||||||
|                 cameraProvider.bindToLifecycle( |                 cameraProvider.bindToLifecycle( | ||||||
|   | |||||||
| @@ -80,7 +80,7 @@ class ViewEntry : Fragment() { | |||||||
|         return (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) |         return (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun setScreenBrightness(brightness: Float?) { |     private fun setScreenBrightness(brightness: Float) { | ||||||
|         requireActivity().window?.attributes?.screenBrightness = brightness |         requireActivity().window?.attributes?.screenBrightness = brightness | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -7,15 +7,15 @@ import org.json.JSONObject | |||||||
| object Kp2aControl { | object Kp2aControl { | ||||||
|  |  | ||||||
|     fun getAddEntryIntent( |     fun getAddEntryIntent( | ||||||
|         fields: HashMap<String?, String?>, |         fields: HashMap<String, String>, | ||||||
|         protectedFields: ArrayList<String?>? |         protectedFields: ArrayList<String>? | ||||||
|     ): Intent { |     ): Intent { | ||||||
|         val outputData = JSONObject((fields as Map<*, *>)).toString() |         val outputData = JSONObject((fields as Map<*, *>)).toString() | ||||||
|         val startKp2aIntent = Intent(Strings.ACTION_START_WITH_TASK) |         val startKp2aIntent = Intent(Strings.ACTION_START_WITH_TASK) | ||||||
|         startKp2aIntent.addCategory(Intent.CATEGORY_DEFAULT) |         startKp2aIntent.addCategory(Intent.CATEGORY_DEFAULT) | ||||||
|         startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) |         startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) | ||||||
|         startKp2aIntent.putExtra("KP2A_APPTASK", "CreateEntryThenCloseTask") |         startKp2aIntent.putExtra("KP2A_APPTASK", "CreateEntryThenCloseTask") | ||||||
|         startKp2aIntent.putExtra("ShowUserNotifications", "false") |         startKp2aIntent.putExtra("ShowUserNotifications", "true") | ||||||
|         startKp2aIntent.putExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA, outputData) |         startKp2aIntent.putExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA, outputData) | ||||||
|         if (protectedFields != null) |         if (protectedFields != null) | ||||||
|             startKp2aIntent.putStringArrayListExtra( |             startKp2aIntent.putStringArrayListExtra( | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ object Strings { | |||||||
|     const val SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY" |     const val SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY" | ||||||
|     const val SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE = |     const val SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE = | ||||||
|         "keepass2android.SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE" |         "keepass2android.SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE" | ||||||
|  |     const val SCOPE_QUERY_CREDENTIALS = "keepass2android.SCOPE_QUERY_CREDENTIALS" | ||||||
|  |  | ||||||
|     const val EXTRA_SCOPES = "keepass2android.EXTRA_SCOPES" |     const val EXTRA_SCOPES = "keepass2android.EXTRA_SCOPES" | ||||||
|     const val EXTRA_PLUGIN_PACKAGE = "keepass2android.EXTRA_PLUGIN_PACKAGE" |     const val EXTRA_PLUGIN_PACKAGE = "keepass2android.EXTRA_PLUGIN_PACKAGE" | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| package net.helcel.fidelity.tools | package net.helcel.fidelity.tools | ||||||
|  |  | ||||||
| import com.google.mlkit.vision.barcode.common.Barcode |  | ||||||
| import com.google.zxing.BarcodeFormat | import com.google.zxing.BarcodeFormat | ||||||
|  |  | ||||||
| object BarcodeFormatConverter { | object BarcodeFormatConverter { | ||||||
| @@ -16,21 +15,39 @@ object BarcodeFormatConverter { | |||||||
|             "UPC_A" -> BarcodeFormat.UPC_A |             "UPC_A" -> BarcodeFormat.UPC_A | ||||||
|             "UPC_E" -> BarcodeFormat.UPC_E |             "UPC_E" -> BarcodeFormat.UPC_E | ||||||
|             "PDF_417" -> BarcodeFormat.PDF_417 |             "PDF_417" -> BarcodeFormat.PDF_417 | ||||||
|  |             "AZTEC" -> BarcodeFormat.AZTEC | ||||||
|  |             "CODABAR" -> BarcodeFormat.CODABAR | ||||||
|  |             "MAXICODE" -> BarcodeFormat.MAXICODE | ||||||
|  |             "DATA_MATRIX" -> BarcodeFormat.DATA_MATRIX | ||||||
|  |             "ITF" -> BarcodeFormat.ITF | ||||||
|  |             "RSS_14" -> BarcodeFormat.RSS_14 | ||||||
|  |             "RSS_EXPANDED" -> BarcodeFormat.RSS_EXPANDED | ||||||
|  |             "UPC_EAN" -> BarcodeFormat.UPC_EAN_EXTENSION | ||||||
|             else -> throw Exception("Unsupported Format: $f") |             else -> throw Exception("Unsupported Format: $f") | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun formatToString(f: Int): String { |     fun formatToString(f: BarcodeFormat): String { | ||||||
|         return when (f) { |         return when (f) { | ||||||
|             Barcode.FORMAT_CODE_128 -> "CODE_128" |             BarcodeFormat.CODE_39 -> "CODE_39" | ||||||
|             Barcode.FORMAT_CODE_39 -> "CODE_39" |             BarcodeFormat.CODE_93 -> "CODE_93" | ||||||
|             Barcode.FORMAT_CODE_93 -> "CODE_93" |             BarcodeFormat.CODE_128 -> "CODE_128" | ||||||
|             Barcode.FORMAT_EAN_8 -> "EAN_8" |             BarcodeFormat.EAN_8 -> "EAN_8" | ||||||
|             Barcode.FORMAT_EAN_13 -> "EAN_13" |             BarcodeFormat.EAN_13 -> "EAN_13" | ||||||
|             Barcode.FORMAT_QR_CODE -> "CODE_QR" |             BarcodeFormat.QR_CODE -> "CODE_QR" | ||||||
|             Barcode.FORMAT_UPC_A -> "UPC_A" |             BarcodeFormat.UPC_A -> "UPC_A" | ||||||
|             Barcode.FORMAT_UPC_E -> "UPC_E" |             BarcodeFormat.UPC_E -> "UPC_E" | ||||||
|             Barcode.FORMAT_PDF417 -> "PDF_417" |             BarcodeFormat.PDF_417 -> "PDF_417" | ||||||
|  |             BarcodeFormat.AZTEC -> "AZTEC" | ||||||
|  |             BarcodeFormat.CODABAR -> "CODABAR" | ||||||
|  |             BarcodeFormat.MAXICODE -> "MAXICODE" | ||||||
|  |             BarcodeFormat.DATA_MATRIX -> "DATA_MATRIX" | ||||||
|  |             BarcodeFormat.ITF -> "ITF" | ||||||
|  |             BarcodeFormat.RSS_14 -> "RSS_14" | ||||||
|  |             BarcodeFormat.RSS_EXPANDED -> "RSS_EXPANDED" | ||||||
|  |             BarcodeFormat.UPC_EAN_EXTENSION -> "UPC_EAN" | ||||||
|             else -> throw Exception("Unsupported Format: $f") |             else -> throw Exception("Unsupported Format: $f") | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,75 +1,61 @@ | |||||||
| package net.helcel.fidelity.tools | package net.helcel.fidelity.tools | ||||||
|  |  | ||||||
| import android.content.ContentValues | import android.graphics.Bitmap | ||||||
| import android.util.Log |  | ||||||
| import androidx.annotation.OptIn | import androidx.annotation.OptIn | ||||||
| import androidx.camera.core.ExperimentalGetImage | import androidx.camera.core.ExperimentalGetImage | ||||||
| import androidx.camera.core.ImageAnalysis | import androidx.camera.core.ImageAnalysis | ||||||
| import androidx.camera.core.ImageProxy | import com.google.zxing.BinaryBitmap | ||||||
| import com.google.mlkit.vision.barcode.BarcodeScanner | import com.google.zxing.MultiFormatReader | ||||||
| import com.google.mlkit.vision.barcode.BarcodeScannerOptions | import com.google.zxing.NotFoundException | ||||||
| import com.google.mlkit.vision.barcode.BarcodeScanning | import com.google.zxing.RGBLuminanceSource | ||||||
| import com.google.mlkit.vision.barcode.common.Barcode | import com.google.zxing.ReaderException | ||||||
| import com.google.mlkit.vision.common.InputImage | import com.google.zxing.common.HybridBinarizer | ||||||
| import net.helcel.fidelity.tools.BarcodeFormatConverter.formatToString | import net.helcel.fidelity.tools.BarcodeFormatConverter.formatToString | ||||||
| import java.util.concurrent.Executors | import java.util.concurrent.Executors | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @OptIn(ExperimentalGetImage::class) | ||||||
| object BarcodeScanner { | object BarcodeScanner { | ||||||
|  |  | ||||||
|     @OptIn(ExperimentalGetImage::class) |     private fun processImage( | ||||||
|     private fun processImageProxy( |         bitmap: Bitmap, | ||||||
|         barcodeScanner: BarcodeScanner, |  | ||||||
|         imageProxy: ImageProxy, |  | ||||||
|         cb: (String?, String?) -> Unit |         cb: (String?, String?) -> Unit | ||||||
|     ) { |     ) { | ||||||
|  |         val binaryBitmap = createBinaryBitmap(bitmap) | ||||||
|         imageProxy.image?.let { image -> |         val reader = MultiFormatReader() | ||||||
|             val inputImage = |         try { | ||||||
|                 InputImage.fromMediaImage( |             val result = reader.decode(binaryBitmap) | ||||||
|                     image, |             cb(result.text, formatToString(result.barcodeFormat)) | ||||||
|                     imageProxy.imageInfo.rotationDegrees |         } catch (e: NotFoundException) { | ||||||
|                 ) |             cb(null, null) | ||||||
|  |         } catch (e: ReaderException) { | ||||||
|             barcodeScanner.process(inputImage) |             cb(null, null) | ||||||
|                 .addOnSuccessListener { barcodeList -> |  | ||||||
|                     val barcode = |  | ||||||
|                         barcodeList.getOrNull(0) |  | ||||||
|                     if (barcode != null) |  | ||||||
|                         cb(barcode.displayValue, formatToString(barcode.format)) |  | ||||||
|                 } |  | ||||||
|                 .addOnFailureListener { |  | ||||||
|                     Log.e(ContentValues.TAG, it.message.orEmpty()) |  | ||||||
|                 }.addOnCompleteListener { |  | ||||||
|                     imageProxy.image?.close() |  | ||||||
|                     imageProxy.close() |  | ||||||
|                 } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getAnalysisUseCase(cb: (String?, String?) -> Unit): ImageAnalysis { |     private fun createBinaryBitmap(bitmap: Bitmap): BinaryBitmap { | ||||||
|         val options = BarcodeScannerOptions.Builder().setBarcodeFormats( |         val pixels = IntArray(bitmap.width * bitmap.height) | ||||||
|             Barcode.FORMAT_CODE_128, |         bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) | ||||||
|             Barcode.FORMAT_CODE_39, |         val source = | ||||||
|             Barcode.FORMAT_CODE_93, |             RGBLuminanceSource(bitmap.width, bitmap.height, pixels) | ||||||
|             Barcode.FORMAT_EAN_8, |         return BinaryBitmap(HybridBinarizer(source)) | ||||||
|             Barcode.FORMAT_EAN_13, |     } | ||||||
|             Barcode.FORMAT_QR_CODE, |  | ||||||
|             Barcode.FORMAT_UPC_A, |  | ||||||
|             Barcode.FORMAT_UPC_E, |  | ||||||
|             Barcode.FORMAT_PDF417 |  | ||||||
|         ).build() |  | ||||||
|         val scanner = BarcodeScanning.getClient(options) |  | ||||||
|         val analysisUseCase = ImageAnalysis.Builder() |  | ||||||
|             .build() |  | ||||||
|  |  | ||||||
|  |     fun analysisUseCase(cb: (String?, String?) -> Unit): ImageAnalysis { | ||||||
|  |         val analysisUseCase = ImageAnalysis.Builder().build() | ||||||
|         analysisUseCase.setAnalyzer( |         analysisUseCase.setAnalyzer( | ||||||
|             Executors.newSingleThreadExecutor() |             Executors.newSingleThreadExecutor() | ||||||
|         ) { imageProxy -> |         ) { imageProxy -> | ||||||
|             processImageProxy(scanner, imageProxy, cb) |             val bitmap = imageProxy.toBitmap() | ||||||
|  |             imageProxy.close() | ||||||
|  |             bitmapUseCase(bitmap, cb) | ||||||
|         } |         } | ||||||
|         return analysisUseCase |         return analysisUseCase | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun bitmapUseCase(bitmap: Bitmap, cb: (String?, String?) -> Unit) { | ||||||
|  |         processImage(bitmap, cb) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -20,4 +20,12 @@ object ErrorToaster { | |||||||
|     fun invalidFormat(activity: Context?) { |     fun invalidFormat(activity: Context?) { | ||||||
|         helper(activity, "Invalid Format", Toast.LENGTH_SHORT) |         helper(activity, "Invalid Format", Toast.LENGTH_SHORT) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun nothingFound(activity: Context?) { | ||||||
|  |         helper(activity, "Nothing Found", Toast.LENGTH_SHORT) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun noPermission(activity: Context?) { | ||||||
|  |         helper(activity, "Missing Permission", Toast.LENGTH_LONG) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,10 +21,10 @@ object KeepassWrapper { | |||||||
|         code: String, |         code: String, | ||||||
|         format: String, |         format: String, | ||||||
|         protectCode: Boolean, |         protectCode: Boolean, | ||||||
|     ): Pair<HashMap<String?, String?>, ArrayList<String?>> { |     ): Pair<HashMap<String, String>, ArrayList<String>> { | ||||||
|  |  | ||||||
|         val fields = HashMap<String?, String?>() |         val fields = HashMap<String, String>() | ||||||
|         val protected = ArrayList<String?>() |         val protected = ArrayList<String>() | ||||||
|         fields[KeepassDef.TitleField] = title |         fields[KeepassDef.TitleField] = title | ||||||
|         fields[KeepassDef.UrlField] = |         fields[KeepassDef.UrlField] = | ||||||
|             "androidapp://" + fragment.requireActivity().packageName |             "androidapp://" + fragment.requireActivity().packageName | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								app/src/main/res/drawable/ic_launcher_foreground.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,58 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:width="108dp" | ||||||
|  |     android:height="108dp" | ||||||
|  |     android:viewportWidth="128" | ||||||
|  |     android:viewportHeight="128"> | ||||||
|  |   <group android:scaleX="1.2833333" | ||||||
|  |       android:scaleY="1.2833333" | ||||||
|  |       android:translateX="-16.612345" | ||||||
|  |       android:translateY="-16.612345"> | ||||||
|  |       <group | ||||||
|  |           android:translateX="34" | ||||||
|  |           android:translateY="26"> | ||||||
|  |           <group | ||||||
|  |               android:scaleX="0.8" | ||||||
|  |               android:scaleY="1.0" | ||||||
|  |               android:translateX="0" | ||||||
|  |               android:translateY="0"> | ||||||
|  |               <path | ||||||
|  |                   android:fillColor="@color/blue" | ||||||
|  |                   android:pathData="M59.959,52.794H12.041c-0.552,0 -1,-0.448 -1,-1v-29.547c0,-0.552 0.448,-1 1,-1h47.918c0.552,0 1,0.448 1,1v29.547C60.959,52.347 60.511,52.794 59.959,52.794z" | ||||||
|  |                   android:strokeWidth="2" | ||||||
|  |                   android:strokeColor="#000000" /> | ||||||
|  |           </group> | ||||||
|  |           <group | ||||||
|  |               android:scaleX="0.4" | ||||||
|  |               android:scaleY="0.5" | ||||||
|  |               android:translateX="27" | ||||||
|  |               android:translateY="15.75"> | ||||||
|  |               <path | ||||||
|  |                   android:fillColor="@color/red" | ||||||
|  |                   android:pathData="M46.5,56l-10,-11l-10,11l0,-45l20,0z" | ||||||
|  |                   android:strokeLineCap="round" | ||||||
|  |                   android:strokeLineJoin="round" /> | ||||||
|  |               <path | ||||||
|  |                   android:fillColor="@color/red2" | ||||||
|  |                   android:fillAlpha="1.0" | ||||||
|  |                   android:pathData="M41.5,11l0,39l5,6l0,-45z" | ||||||
|  |                   android:strokeColor="#00000000" /> | ||||||
|  |  | ||||||
|  |           </group> | ||||||
|  |           <group | ||||||
|  |               android:scaleX="0.75" | ||||||
|  |               android:scaleY="0.75" | ||||||
|  |               android:translateX="6" | ||||||
|  |               android:translateY="10"> | ||||||
|  |               <path | ||||||
|  |                   android:fillColor="#00000000" | ||||||
|  |                   android:pathData="M9,21V52 M12,21V52 M20,21V50 M28,21V50 M15,50V21H17V50H15 M23,50V21H25V50H23 M31,50V21H32V50H31 M35,21V52 M38,21V52" | ||||||
|  |                   android:strokeWidth="2" | ||||||
|  |                   android:strokeColor="#000" | ||||||
|  |                   android:strokeLineCap="round" | ||||||
|  |                   android:strokeLineJoin="round" /> | ||||||
|  |           </group> | ||||||
|  |  | ||||||
|  |       </group> | ||||||
|  |   </group> | ||||||
|  | </vector> | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> |  | ||||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> |  | ||||||
|     <item |  | ||||||
|         android:width="128dp" |  | ||||||
|         android:height="128dp" |  | ||||||
|         android:gravity="center" |  | ||||||
|         android:drawable="@drawable/card" /> |  | ||||||
|     <item |  | ||||||
|         android:width="64dp" |  | ||||||
|         android:height="64dp" |  | ||||||
|         android:drawable="@drawable/barcode" |  | ||||||
|         android:gravity="center" |  | ||||||
|         android:right="32dp" /> |  | ||||||
|     <item |  | ||||||
|         android:width="52dp" |  | ||||||
|         android:height="52dp" |  | ||||||
|         android:drawable="@drawable/bookmark" |  | ||||||
|         android:gravity="center" |  | ||||||
|         android:left="72dp" |  | ||||||
|         android:bottom="20dp" /> |  | ||||||
| </layer-list> |  | ||||||
							
								
								
									
										53
									
								
								app/src/main/res/drawable/logo_g.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,53 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:width="200dp" | ||||||
|  |     android:height="200dp" | ||||||
|  |     android:viewportWidth="128" | ||||||
|  |     android:viewportHeight="128"> | ||||||
|  |     <group | ||||||
|  |         android:translateX="34" | ||||||
|  |         android:translateY="26"> | ||||||
|  |         <group | ||||||
|  |             android:scaleX="0.8" | ||||||
|  |             android:scaleY="1.0" | ||||||
|  |             android:translateX="0" | ||||||
|  |             android:translateY="0"> | ||||||
|  |             <path | ||||||
|  |                 android:fillColor="@color/blue" | ||||||
|  |                 android:pathData="M59.959,52.794H12.041c-0.552,0 -1,-0.448 -1,-1v-29.547c0,-0.552 0.448,-1 1,-1h47.918c0.552,0 1,0.448 1,1v29.547C60.959,52.347 60.511,52.794 59.959,52.794z" | ||||||
|  |                 android:strokeWidth="2" | ||||||
|  |                 android:strokeColor="#000000" /> | ||||||
|  |         </group> | ||||||
|  |         <group | ||||||
|  |             android:scaleX="0.4" | ||||||
|  |             android:scaleY="0.5" | ||||||
|  |             android:translateX="27" | ||||||
|  |             android:translateY="15.75"> | ||||||
|  |             <path | ||||||
|  |                 android:fillColor="@color/red" | ||||||
|  |                 android:pathData="M46.5,56l-10,-11l-10,11l0,-45l20,0z" | ||||||
|  |                 android:strokeLineCap="round" | ||||||
|  |                 android:strokeLineJoin="round" /> | ||||||
|  |             <path | ||||||
|  |                 android:fillColor="@color/red2" | ||||||
|  |                 android:fillAlpha="1.0" | ||||||
|  |                 android:pathData="M41.5,11l0,39l5,6l0,-45z" | ||||||
|  |                 android:strokeColor="#00000000" /> | ||||||
|  |  | ||||||
|  |         </group> | ||||||
|  |         <group | ||||||
|  |             android:scaleX="0.75" | ||||||
|  |             android:scaleY="0.75" | ||||||
|  |             android:translateX="6" | ||||||
|  |             android:translateY="10"> | ||||||
|  |             <path | ||||||
|  |                 android:fillColor="#00000000" | ||||||
|  |                 android:pathData="M9,21V52 M12,21V52 M20,21V50 M28,21V50 M15,50V21H17V50H15 M23,50V21H25V50H23 M31,50V21H32V50H31 M35,21V52 M38,21V52" | ||||||
|  |                 android:strokeWidth="2" | ||||||
|  |                 android:strokeColor="#000" | ||||||
|  |                 android:strokeLineCap="round" | ||||||
|  |                 android:strokeLineJoin="round" /> | ||||||
|  |         </group> | ||||||
|  |  | ||||||
|  |     </group> | ||||||
|  | </vector> | ||||||
							
								
								
									
										22
									
								
								app/src/main/res/drawable/open.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | |||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:width="72dp" | ||||||
|  |     android:height="72dp" | ||||||
|  |     android:viewportWidth="58" | ||||||
|  |     android:viewportHeight="58"> | ||||||
|  |   <group android:translateX="-10" android:translateY="-8"> | ||||||
|  |   <path | ||||||
|  |       android:pathData="m57.008,20.304v-3.356l-27.338,-0.002c-0.198,0 -0.359,-0.165 -0.359,-0.368l-0.069,-1.517c-0.116,-1.788 -1.34,-3.003 -2.997,-3.003h-11.287c-1.657,0 -3,1.343 -3,3v40.943" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="m17.027,55.568c-0.59,1.954 -2.972,4.139 -4.646,4.394l44.665,0.011c1.657,0 2.323,-0.439 3,-3s7,-31.657 7,-31.657c0,-0.552 -0.448,-1 -1,-1H24.965c-0.552,0 -1,0.448 -1,1 0,0 -6.348,28.299 -6.938,30.253Z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   </group> | ||||||
|  | </vector> | ||||||
							
								
								
									
										302
									
								
								app/src/main/res/drawable/qr.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,302 @@ | |||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:width="72dp" | ||||||
|  |     android:height="72dp" | ||||||
|  |     android:viewportWidth="58" | ||||||
|  |     android:viewportHeight="58"> | ||||||
|  |   <group android:translateX="-8" android:translateY="-8"> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M20,20h4v4h-4z" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M20,48h4v4h-4z" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M48,20h4v4h-4z" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M18,40m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M16,38m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M20,38m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M34,46m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M40,38m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M40,28m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M32,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M46,32m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M52,32m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M52,44m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M54,48m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M56,56m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M32,56m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M44,56m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M46,54m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M44,52m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M16,32m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M40,54m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" | ||||||
|  |       android:fillColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M12,12h48v48h-48z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M16,16h12v12h-12z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M20,20h4v4h-4z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M16,44h12v12h-12z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M20,48h4v4h-4z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M44,16h12v12h-12z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M48,20h4v4h-4z" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M18,36V34H26" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M20,34V32" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M24,34V40" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M24,38H26" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M38,32V30" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M56,34H54" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M42,42H44V40" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M28,32H30" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M34,32H40" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M38,16V20H36V28" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M36,26H32V28" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M36,20H32" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M36,22H34V18" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M28,36H36" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M30,36V40H28" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M34,36V38" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M32,44V42H38V48H42V46H50V56" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M36,40V44H42M46,40H42V48H44" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M48,34V38H50V42H48V46" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M50,38V36H52" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M52,50H48V52" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M32,52H34V54H36V50" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M56,32V38H54" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M44,36V34" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M56,42V44" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M54,52H56" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   <path | ||||||
|  |       android:pathData="M40,22V24" | ||||||
|  |       android:strokeLineJoin="round" | ||||||
|  |       android:strokeWidth="2" | ||||||
|  |       android:fillColor="#00000000" | ||||||
|  |       android:strokeColor="#000" | ||||||
|  |       android:strokeLineCap="round"/> | ||||||
|  |   </group> | ||||||
|  | </vector> | ||||||
| @@ -11,6 +11,7 @@ | |||||||
|         android:id="@+id/container" |         android:id="@+id/container" | ||||||
|         android:layout_width="match_parent" |         android:layout_width="match_parent" | ||||||
|         android:layout_height="match_parent" |         android:layout_height="match_parent" | ||||||
|  |         android:background="@color/black" | ||||||
|         tools:ignore="MergeRootFrame" /> |         tools:ignore="MergeRootFrame" /> | ||||||
|  |  | ||||||
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | </androidx.coordinatorlayout.widget.CoordinatorLayout> | ||||||
| @@ -3,6 +3,7 @@ | |||||||
|     xmlns:tools="http://schemas.android.com/tools" |     xmlns:tools="http://schemas.android.com/tools" | ||||||
|     android:layout_width="match_parent" |     android:layout_width="match_parent" | ||||||
|     android:layout_height="match_parent" |     android:layout_height="match_parent" | ||||||
|  |     android:background="@color/black" | ||||||
|     android:orientation="vertical" |     android:orientation="vertical" | ||||||
|     tools:context=".activity.fragment.Launcher"> |     tools:context=".activity.fragment.Launcher"> | ||||||
|  |  | ||||||
| @@ -56,6 +57,16 @@ | |||||||
|                 app:maxImageSize="32dp" |                 app:maxImageSize="32dp" | ||||||
|                 app:srcCompat="@drawable/camera" /> |                 app:srcCompat="@drawable/camera" /> | ||||||
|  |  | ||||||
|  |             <com.google.android.material.floatingactionbutton.FloatingActionButton | ||||||
|  |                 android:id="@+id/btnOpen" | ||||||
|  |                 android:layout_width="wrap_content" | ||||||
|  |                 android:layout_height="wrap_content" | ||||||
|  |                 android:layout_margin="8dp" | ||||||
|  |                 android:contentDescription="@string/open" | ||||||
|  |                 app:fabCustomSize="46dp" | ||||||
|  |                 app:maxImageSize="32dp" | ||||||
|  |                 app:srcCompat="@drawable/open" /> | ||||||
|  |  | ||||||
|             <com.google.android.material.floatingactionbutton.FloatingActionButton |             <com.google.android.material.floatingactionbutton.FloatingActionButton | ||||||
|                 android:id="@+id/btnManual" |                 android:id="@+id/btnManual" | ||||||
|                 android:layout_width="wrap_content" |                 android:layout_width="wrap_content" | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ | |||||||
|         android:contentDescription="@string/manual" /> |         android:contentDescription="@string/manual" /> | ||||||
|  |  | ||||||
|     <com.google.android.material.progressindicator.CircularProgressIndicator |     <com.google.android.material.progressindicator.CircularProgressIndicator | ||||||
|  |         android:id="@+id/ScanActive" | ||||||
|         android:layout_width="wrap_content" |         android:layout_width="wrap_content" | ||||||
|         android:layout_height="wrap_content" |         android:layout_height="wrap_content" | ||||||
|         android:layout_alignParentBottom="true" |         android:layout_alignParentBottom="true" | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <background android:drawable="@color/ic_launcher_background"/> | ||||||
|  |     <foreground android:drawable="@drawable/ic_launcher_foreground"/> | ||||||
|  | </adaptive-icon> | ||||||
							
								
								
									
										5
									
								
								app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <background android:drawable="@color/ic_launcher_background"/> | ||||||
|  |     <foreground android:drawable="@drawable/ic_launcher_foreground"/> | ||||||
|  | </adaptive-icon> | ||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-hdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-mdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 10 KiB | 
							
								
								
									
										14
									
								
								app/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <color name="black">#FF000000</color> | ||||||
|  |     <color name="darkgray">#FF0C1D2E</color> | ||||||
|  |     <color name="gray">#425F7C</color> | ||||||
|  |     <color name="lightgray">#FF93A9BE</color> | ||||||
|  |     <color name="white">#FFF0F3F7</color> | ||||||
|  |  | ||||||
|  |     <color name="blue">#7DB9F5</color> | ||||||
|  |     <color name="blue2">#3193F5</color> | ||||||
|  |     <color name="red">#F57D7D</color> | ||||||
|  |     <color name="red2">#F53131</color> | ||||||
|  |  | ||||||
|  | </resources> | ||||||
							
								
								
									
										4
									
								
								app/src/main/res/values/ic_launcher_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <color name="ic_launcher_background">#0C1D2E</color> | ||||||
|  | </resources> | ||||||
| @@ -15,15 +15,20 @@ | |||||||
|     <string name="code">Code</string> |     <string name="code">Code</string> | ||||||
|     <string name="format">Format</string> |     <string name="format">Format</string> | ||||||
|     <string name="save">Save</string> |     <string name="save">Save</string> | ||||||
|  |     <string name="open">Open</string> | ||||||
|     <string-array name="format_array"> |     <string-array name="format_array"> | ||||||
|         <item>CODE_128</item> |  | ||||||
|         <item>CODE_39</item> |         <item>CODE_39</item> | ||||||
|         <item>CODE_93</item> |         <item>CODE_93</item> | ||||||
|  |         <item>CODE_128</item> | ||||||
|         <item>EAN_8</item> |         <item>EAN_8</item> | ||||||
|         <item>EAN_13</item> |         <item>EAN_13</item> | ||||||
|         <item>CODE_QR</item> |         <item>CODE_QR</item> | ||||||
|         <item>UPC_A</item> |         <item>UPC_A</item> | ||||||
|         <item>UPC_E</item> |         <item>UPC_E</item> | ||||||
|         <item>PDF_417</item> |         <item>PDF_417</item> | ||||||
|  |         <item>AZTEC</item> | ||||||
|  |         <item>CODABAR</item> | ||||||
|  |         <item>DATA_MATRIX</item> | ||||||
|  |         <item>ITF</item> | ||||||
|     </string-array> |     </string-array> | ||||||
| </resources> | </resources> | ||||||
| @@ -2,11 +2,10 @@ | |||||||
| <resources> | <resources> | ||||||
|  |  | ||||||
|     <style name="Theme.Fidelity" parent="Theme.MaterialComponents.DayNight.NoActionBar"> |     <style name="Theme.Fidelity" parent="Theme.MaterialComponents.DayNight.NoActionBar"> | ||||||
|  |         <item name="colorPrimary">@color/blue</item> | ||||||
|         <item name="colorPrimary">#7DB9F5</item> |         <item name="colorPrimaryVariant">@color/blue</item> | ||||||
|         <item name="colorPrimaryVariant">#7DB9F5</item> |         <item name="colorSecondary">@color/blue</item> | ||||||
|         <item name="colorSecondary">#7DB9F5</item> |         <item name="colorSecondaryVariant">@color/blue</item> | ||||||
|         <item name="colorSecondaryVariant">#7DB9F5</item> |         <item name="colorOnPrimary">@color/darkgray</item> | ||||||
|         <item name="colorOnPrimary">#030B12</item> |  | ||||||
|     </style> |     </style> | ||||||
| </resources> | </resources> | ||||||
| @@ -1,7 +1,8 @@ | |||||||
| // Top-level build file where you can add configuration options common to all sub-projects/modules. | // Top-level build file where you can add configuration options common to all sub-projects/modules. | ||||||
|  |  | ||||||
| plugins { | plugins { | ||||||
|     id 'com.android.application' version '8.3.1' apply false |     id 'com.android.application' version '8.7.2' apply false | ||||||
|     id 'com.android.library' version '8.3.1' apply false |     id 'com.android.library' version '8.7.2' apply false | ||||||
|     id 'org.jetbrains.kotlin.android' version '1.9.23' apply false |     id 'org.jetbrains.kotlin.android' version '2.0.21' apply false | ||||||
|  |     id 'com.autonomousapps.dependency-analysis' version '2.5.0' apply true | ||||||
| } | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,6 +1,6 @@ | |||||||
| distributionBase=GRADLE_USER_HOME | distributionBase=GRADLE_USER_HOME | ||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip | ||||||
| networkTimeout=10000 | networkTimeout=10000 | ||||||
| validateDistributionUrl=true | validateDistributionUrl=true | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -15,6 +15,8 @@ | |||||||
| # See the License for the specific language governing permissions and | # See the License for the specific language governing permissions and | ||||||
| # limitations under the License. | # limitations under the License. | ||||||
| # | # | ||||||
|  | # SPDX-License-Identifier: Apache-2.0 | ||||||
|  | # | ||||||
|  |  | ||||||
| ############################################################################## | ############################################################################## | ||||||
| # | # | ||||||
| @@ -55,7 +57,7 @@ | |||||||
| #       Darwin, MinGW, and NonStop. | #       Darwin, MinGW, and NonStop. | ||||||
| # | # | ||||||
| #   (3) This script is generated from the Groovy template | #   (3) This script is generated from the Groovy template | ||||||
| #       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt | #       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt | ||||||
| #       within the Gradle project. | #       within the Gradle project. | ||||||
| # | # | ||||||
| #       You can find Gradle at https://github.com/gradle/gradle/. | #       You can find Gradle at https://github.com/gradle/gradle/. | ||||||
| @@ -84,7 +86,8 @@ done | |||||||
| # shellcheck disable=SC2034 | # shellcheck disable=SC2034 | ||||||
| APP_BASE_NAME=${0##*/} | APP_BASE_NAME=${0##*/} | ||||||
| # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) | ||||||
| APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s | ||||||
|  | ' "$PWD" ) || exit | ||||||
|  |  | ||||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||||
| MAX_FD=maximum | MAX_FD=maximum | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -13,6 +13,8 @@ | |||||||
| @rem See the License for the specific language governing permissions and | @rem See the License for the specific language governing permissions and | ||||||
| @rem limitations under the License. | @rem limitations under the License. | ||||||
| @rem | @rem | ||||||
|  | @rem SPDX-License-Identifier: Apache-2.0 | ||||||
|  | @rem | ||||||
|  |  | ||||||
| @if "%DEBUG%"=="" @echo off | @if "%DEBUG%"=="" @echo off | ||||||
| @rem ########################################################################## | @rem ########################################################################## | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								metadata/en-US/full_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | <p><i>Keepass-Fidelity</i> adds an interface to view/save barcodes (QR included) to Keepass through the plugin interface of the Keepass2Android app.</p><p><br></p><ul><li><b>Launcher:</b> view and launch recent entries (a per entry flag can disable this behaviour)</li><li><b>View:</b> view entries from the history or queried from Keepass2Android</li><li><b>Create:</b> add entries from the camera, an image of by filling out a form. The entry is then created in the Keepass2Android app</li><li><b>Data:</b> the app uses the following data Title (entry name), barcode type (QR, UPC, ...), barcode content (number/text content) and a "secure" flag (enable/disable caching the entry).</li></ul> | ||||||
							
								
								
									
										
											BIN
										
									
								
								metadata/en-US/images/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								metadata/en-US/images/phoneScreenshots/edit.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 34 KiB | 
							
								
								
									
										
											BIN
										
									
								
								metadata/en-US/images/phoneScreenshots/launcher.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								metadata/en-US/images/phoneScreenshots/view.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 25 KiB | 
							
								
								
									
										1
									
								
								metadata/en-US/permission_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | <ul><li><b>CAMERA:</b> necessary for importing barcodes from camera</li><li><b>READ_MEDIA_VISUAL_USER_SELECTED:</b> necessary for the importing barcode from images</li></ul> | ||||||
							
								
								
									
										1
									
								
								metadata/en-US/short_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | Fidelity (Membership/Loyalty) Card plugin for Keepass2Android | ||||||
| @@ -14,5 +14,6 @@ dependencyResolutionManagement { | |||||||
|         maven { url 'https://jitpack.io' } |         maven { url 'https://jitpack.io' } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| rootProject.name = "Fidelity" | rootProject.name = "Fidelity" | ||||||
| include ':app' | include ':app' | ||||||
|   | |||||||