21 Commits

Author SHA1 Message Date
6596f347a1 Updated icon 2024-03-24 15:41:26 +01:00
a2dd009533 Fixed versioning 2024-03-24 13:29:13 +01:00
4104104b16 minor release 2024-03-24 13:17:09 +01:00
0d838b6209 Removed missing encoder 2024-03-24 13:11:15 +01:00
1d41671fb6 prep 1.1 2024-03-24 13:01:46 +01:00
84ebdcc9a8 Support more formats & cleanup 2024-03-24 13:00:22 +01:00
8181da421e Deleted GoogleML usage 2024-03-24 12:40:33 +01:00
af97381bdb Fix Readme 2024-03-24 11:37:28 +01:00
ba94beab37 Fix Readme 2024-03-24 11:36:35 +01:00
19b0f91852 Update README.md 2024-03-24 11:32:34 +01:00
3b0bf2097e Github images 2024-03-24 11:16:26 +01:00
455c95021b LICENSE 2024-03-24 10:45:37 +01:00
78ad7f983f CI Fix 2024-03-24 10:34:02 +01:00
0a0b55294f Fix CI 2024-03-24 10:28:30 +01:00
040b9c3af4 Fix CI 2024-03-24 10:26:31 +01:00
796c76f36c CI Signing 2024-03-24 10:23:30 +01:00
517f0240e3 CI release 2024-03-23 15:12:15 +01:00
b02920ca41 CI Autorelease 2024-03-23 15:03:09 +01:00
b289648260 CI Artifact 2024-03-23 14:25:04 +01:00
b6de7ca409 CI fix tag 2024-03-23 14:13:37 +01:00
12fb04974e CI on tag 2024-03-23 14:09:54 +01:00
30 changed files with 433 additions and 85 deletions

BIN
.github/images/apk.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
.github/images/edit.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
.github/images/izzy.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
.github/images/launcher.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
.github/images/view.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,3 +1,4 @@
#file: noinspection SpellCheckingInspection
name: CI-Android APK name: CI-Android APK
@ -7,18 +8,30 @@ env:
on: on:
push: push:
branches: [ release ] branches: [ main ]
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
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- 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@v2 - uses: gradle/wrapper-validation-action@v2
- name: create and checkout branch - name: create and checkout branch
@ -37,8 +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:
# name: app.apk
# path: app/build/outputs/apk/release/app-release.apk
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with: with:
name: app files: |
path: app/build/outputs/apk/release/*.apk app/build/outputs/apk/release/app-release.apk

2
.gitignore vendored
View File

@ -13,3 +13,5 @@ captures/
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
keystore.properties
key.jks

24
LICENSE Normal file
View 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>

View File

@ -0,0 +1,69 @@
<!--suppress ALL -->
<div align="center">
<h1>Keepass Fidelity</h1>
<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=".github/images/launcher.jpg" alt="Launcher" style="width: 100%; height: 100%;"></td>
<td style="width: 33%; height: 100px;"><img src=".github/images/view.jpg" alt="View" style="width: 100%; height: 100%;"></td>
<td style="width: 33%; height: 100px;"><img src=".github/images/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://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 the scanning of barcodes
## 📝 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>
```

View File

@ -5,17 +5,30 @@ plugins {
} }
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 {
@ -26,6 +39,7 @@ android {
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 +59,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.0.4' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.4'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.camera:camera-camera2:1.3.2'
implementation 'androidx.camera:camera-lifecycle:1.3.2' implementation 'androidx.camera:camera-lifecycle:1.3.2'
implementation 'androidx.camera:camera-view:1.3.2' implementation 'androidx.camera:camera-view:1.3.2'
runtimeOnly 'androidx.camera:camera-camera2:1.3.2'
implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.google.android.material:material:1.11.0' 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
View 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

View File

@ -1,13 +1,13 @@
<?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="5"
android:versionName="1.0"> android:versionName="1.1c">
<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" />
<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

View File

@ -45,6 +45,7 @@ class Scanner : Fragment() {
return binding.root return binding.root
} }
private fun startCreateEntry() { private fun startCreateEntry() {
val createEntryFragment = CreateEntry() val createEntryFragment = CreateEntry()
createEntryFragment.arguments = createEntryFragment.arguments =
@ -89,13 +90,14 @@ class Scanner : Fragment() {
} }
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
val analysisUseCase = getAnalysisUseCase { code, format -> val analysisUseCase = getAnalysisUseCase { code, format ->
if (code != null && format != null) { if (!code.isNullOrEmpty() && !format.isNullOrEmpty()) {
this.code = code this.code = code
this.fmt = format this.fmt = format
binding.btnScanDone.isEnabled = true }
val isDone = this.code.isNotEmpty() && this.fmt.isNotEmpty()
} else { requireActivity().runOnUiThread {
binding.btnScanDone.isEnabled = false binding.btnScanDone.isEnabled = isDone
binding.ScanActive.isEnabled = !isDone
} }
} }
try { try {

View File

@ -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")
} }
} }

View File

@ -1,16 +1,16 @@
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 androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanner import com.google.zxing.BinaryBitmap
import com.google.mlkit.vision.barcode.BarcodeScannerOptions import com.google.zxing.MultiFormatReader
import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.zxing.NotFoundException
import com.google.mlkit.vision.barcode.common.Barcode import com.google.zxing.RGBLuminanceSource
import com.google.mlkit.vision.common.InputImage import com.google.zxing.ReaderException
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
@ -19,57 +19,39 @@ object BarcodeScanner {
@OptIn(ExperimentalGetImage::class) @OptIn(ExperimentalGetImage::class)
private fun processImageProxy( private fun processImageProxy(
barcodeScanner: BarcodeScanner,
imageProxy: ImageProxy, imageProxy: ImageProxy,
cb: (String?, String?) -> Unit cb: (String?, String?) -> Unit
) { ) {
val bitmap = imageProxy.toBitmap() // Convert ImageProxy to Bitmap
imageProxy.image?.let { image -> val binaryBitmap = createBinaryBitmap(bitmap)
val inputImage = val reader = MultiFormatReader()
InputImage.fromMediaImage( try {
image, val result = reader.decode(binaryBitmap)
imageProxy.imageInfo.rotationDegrees cb(result.text, formatToString(result.barcodeFormat))
) } catch (e: NotFoundException) {
cb(null, null)
barcodeScanner.process(inputImage) } catch (e: ReaderException) {
.addOnSuccessListener { barcodeList -> cb(null, null)
val barcode = } finally {
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() imageProxy.close()
} }
} }
private fun createBinaryBitmap(bitmap: Bitmap): BinaryBitmap {
val pixels = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
val source =
RGBLuminanceSource(bitmap.width, bitmap.height, pixels)
return BinaryBitmap(HybridBinarizer(source))
} }
fun getAnalysisUseCase(cb: (String?, String?) -> Unit): ImageAnalysis { fun getAnalysisUseCase(cb: (String?, String?) -> Unit): ImageAnalysis {
val options = BarcodeScannerOptions.Builder().setBarcodeFormats( val analysisUseCase = ImageAnalysis.Builder().build()
Barcode.FORMAT_CODE_128,
Barcode.FORMAT_CODE_39,
Barcode.FORMAT_CODE_93,
Barcode.FORMAT_EAN_8,
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()
analysisUseCase.setAnalyzer( analysisUseCase.setAnalyzer(
Executors.newSingleThreadExecutor() Executors.newSingleThreadExecutor()
) { imageProxy -> ) { imageProxy ->
processImageProxy(scanner, imageProxy, cb) processImageProxy(imageProxy, cb)
} }
return analysisUseCase return analysisUseCase
} }
} }

View 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/logo_g"/>
</adaptive-icon>

View File

@ -1,5 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="256dp"
android:height="256dp"
android:viewportWidth="256"
android:viewportHeight="256"
android:gravity="center"
>
<layer-list>
<item <item
android:width="128dp" android:width="128dp"
android:height="128dp" android:height="128dp"
@ -18,4 +26,5 @@
android:gravity="center" android:gravity="center"
android:left="72dp" android:left="72dp"
android:bottom="20dp" /> android:bottom="20dp" />
</layer-list></item>
</layer-list> </layer-list>

View File

@ -0,0 +1,167 @@
<?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:translateX="28"
android:translateY="28">
<group>
<path
android:fillColor="#92D3F5"
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.5"
android:scaleY="0.5"
android:translateX="32"
android:translateY="16">
<path
android:fillColor="#EA5A47"
android:pathData="M46.5,56l-10,-11.151l-10,11.151l0,-45.042l20,0z"
android:strokeWidth="2"
android:strokeColor="#00000000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#D22F27"
android:pathData="M41.864,12.03l0,37.854l4.523,5.044l0,-42.898z"
android:strokeColor="#00000000" />
<path
android:fillColor="#00000000"
android:pathData="M46.5,56l-10,-11.151l-10,11.151l0,-45.042l20,0z"
android:strokeWidth="2"
android:strokeColor="#000000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M46.5,56l-10,-11.151l-10,11.151l0,-45.042l20,0z"
android:strokeWidth="2"
android:strokeColor="#000000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
<group
android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="10"
android:translateY="18">
<path
android:fillColor="#00000000"
android:pathData="M9,21V52"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M12,21V52"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M20,21V50"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M28,21V50"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#000"
android:pathData="M15,50V21H17V50H15Z"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#000"
android:pathData="M23,50V21H25V50H23Z"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#000"
android:pathData="M31,50V21H32V50H31Z"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M46,21V50"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M49,21V50"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M57,21V50"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#000"
android:pathData="M41,50V21H43V50H41Z"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#000"
android:pathData="M52,50V21H54V50H52Z"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M60,21V52"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M63,21V52"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M35,21V52"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<path
android:fillColor="#00000000"
android:pathData="M38,21V52"
android:strokeWidth="2"
android:strokeColor="#000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
</group>
</vector>

View File

@ -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"

View 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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#393939</color>
</resources>

View File

@ -16,14 +16,18 @@
<string name="format">Format</string> <string name="format">Format</string>
<string name="save">Save</string> <string name="save">Save</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>

View File

@ -4,4 +4,5 @@ plugins {
id 'com.android.application' version '8.3.1' apply false id 'com.android.application' version '8.3.1' apply false
id 'com.android.library' version '8.3.1' apply false id 'com.android.library' version '8.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.9.23' apply false id 'org.jetbrains.kotlin.android' version '1.9.23' apply false
id 'com.autonomousapps.dependency-analysis' version '1.30.0' apply true
} }

View File

@ -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'