Compare commits
112 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
83e2cf733e | ||
|
3214d772b2 | ||
|
40c3f39c49 | ||
|
6215ffa7b6 | ||
|
bf073da67b | ||
|
49fe5ca037 | ||
|
62f854db27 | ||
|
aea6fa6c69 | ||
|
029a1fcde7 | ||
|
92c99bec22 | ||
|
663c1236a4 | ||
|
a9582ffb05 | ||
|
b11fb89bd9 | ||
|
1e6bebe853 | ||
|
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 | ||
|
040b9c3af4 | ||
|
796c76f36c |
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 |
28
.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
|
||||||
@ -23,7 +24,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: gradle/wrapper-validation-action@v2
|
|
||||||
|
- name: set up secrets
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.RELEASE_KEYSTORE }}" > keystore.asc
|
||||||
|
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 key.asc > app/key.jks
|
||||||
|
|
||||||
|
- 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'
|
||||||
@ -41,14 +50,15 @@ jobs:
|
|||||||
- name: Build APK
|
- name: Build APK
|
||||||
run: ./gradlew assemble
|
run: ./gradlew assemble
|
||||||
|
|
||||||
- name: Upload APK
|
# - name: Upload APK
|
||||||
uses: actions/upload-artifact@v4
|
# uses: actions/upload-artifact@v4
|
||||||
with:
|
# with:
|
||||||
name: app.apk
|
# name: app.apk
|
||||||
path: app/build/outputs/apk/release/app-release-unsigned.apk
|
# path: app/build/outputs/apk/release/app-release.apk
|
||||||
|
|
||||||
- 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-unsigned.apk
|
app/build/outputs/apk/release/app-release.apk
|
2
.gitignore
vendored
@ -13,3 +13,5 @@ captures/
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
|
keystore.properties
|
||||||
|
key.jks
|
||||||
|
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,31 +1,46 @@
|
|||||||
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.1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def keystorePropertiesFile = rootProject.file("app/keystore.properties")
|
||||||
|
def keystoreProperties = new Properties()
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'net.helcel.fidelity'
|
namespace 'net.helcel.fidelity'
|
||||||
compileSdk 34
|
compileSdk 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId 'net.helcel.fidelity'
|
applicationId 'net.helcel.fidelity'
|
||||||
resValue "string", "app_name", "Keepass Fideity"
|
resValue "string", "app_name", "Keepass Fidelity"
|
||||||
minSdk 28
|
minSdk 28
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 1
|
}
|
||||||
versionName "1.0"
|
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
keyAlias keystoreProperties['keyAlias']
|
||||||
|
keyPassword keystoreProperties['keyPassword']
|
||||||
|
storeFile file(keystoreProperties['storeFile'])
|
||||||
|
storePassword keystoreProperties['storePassword']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
debuggable true
|
debuggable true
|
||||||
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources false
|
shrinkResources false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,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.4'
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.4'
|
implementation 'androidx.camera:camera-lifecycle:1.4.1'
|
||||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
implementation 'androidx.camera:camera-view:1.4.1'
|
||||||
implementation 'androidx.core:core-ktx:1.12.0'
|
runtimeOnly 'androidx.camera:camera-camera2:1.4.1'
|
||||||
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'
|
|
||||||
|
|
||||||
}
|
}
|
13
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Gson uses generic type information stored in a class file when working with
|
||||||
|
# fields. Proguard removes such information by default, keep it.
|
||||||
|
-keepattributes Signature
|
||||||
|
|
||||||
|
# This is also needed for R8 in compat mode since multiple
|
||||||
|
# optimizations will remove the generic signature such as class
|
||||||
|
# merging and argument removal. See:
|
||||||
|
# https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#troubleshooting-gson-gson
|
||||||
|
-keep class com.google.gson.reflect.TypeToken { *; }
|
||||||
|
-keep class * extends com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
# Optional. For using GSON @Expose annotation
|
||||||
|
-keepattributes AnnotationDefault,RuntimeVisibleAnnotations
|
@ -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() {
|
private fun scannerResult(code: String?, format: String?) {
|
||||||
ActivityCompat.requestPermissions(
|
if (!code.isNullOrEmpty() && !format.isNullOrEmpty()) {
|
||||||
requireActivity(),
|
this.code = code
|
||||||
arrayOf(Manifest.permission.CAMERA),
|
this.fmt = format
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
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.8.0' apply false
|
||||||
id 'com.android.library' version '8.3.1' apply false
|
id 'com.android.library' version '8.8.0' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.9.23' apply false
|
id 'org.jetbrains.kotlin.android' version '2.1.0' apply false
|
||||||
|
id 'com.autonomousapps.dependency-analysis' version '2.7.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.12-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
6
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,7 @@ 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\n' "$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'
|
||||||
|