From d81922d2c9fb35a86fe4a02867752b9f70431c42 Mon Sep 17 00:00:00 2001 From: soraefir Date: Fri, 29 Mar 2024 13:26:10 +0100 Subject: [PATCH] File Scanner & Metadata --- README.md | 8 +- app/src/main/AndroidManifest.xml | 3 + .../fidelity/activity/fragment/FileScanner.kt | 107 ++++++++++++++++++ .../fidelity/activity/fragment/Launcher.kt | 9 ++ .../fidelity/activity/fragment/Scanner.kt | 64 +++++------ .../helcel/fidelity/tools/BarcodeScanner.kt | 22 ++-- .../net/helcel/fidelity/tools/ErrorToaster.kt | 8 ++ app/src/main/res/drawable/open.xml | 22 ++++ app/src/main/res/layout/frag_launcher.xml | 10 ++ app/src/main/res/values/strings.xml | 1 + metadata/en-US/full_description.txt | 1 + metadata/en-US/images/icon.png | Bin 0 -> 22132 bytes .../en-US/images/phoneScreenshots}/edit.jpg | Bin .../images/phoneScreenshots}/launcher.jpg | Bin .../en-US/images/phoneScreenshots}/view.jpg | Bin metadata/en-US/short_description.txt | 1 + 16 files changed, 205 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/net/helcel/fidelity/activity/fragment/FileScanner.kt create mode 100644 app/src/main/res/drawable/open.xml create mode 100644 metadata/en-US/full_description.txt create mode 100644 metadata/en-US/images/icon.png rename {.github/images => metadata/en-US/images/phoneScreenshots}/edit.jpg (100%) rename {.github/images => metadata/en-US/images/phoneScreenshots}/launcher.jpg (100%) rename {.github/images => metadata/en-US/images/phoneScreenshots}/view.jpg (100%) create mode 100644 metadata/en-US/short_description.txt diff --git a/README.md b/README.md index 837d0d2..5bd4de6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

Keepass Fidelity

- Logo + Logo

A minimalist fidelity/loyalty card plugin

@@ -18,9 +18,9 @@
- - - + + +
LauncherViewEditLauncherViewEdit
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 82bd4a5..3c6e43d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,10 @@ android:versionName="1.1c"> + + + = 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() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/helcel/fidelity/activity/fragment/Launcher.kt b/app/src/main/java/net/helcel/fidelity/activity/fragment/Launcher.kt index 21fd1a1..54ce24e 100644 --- a/app/src/main/java/net/helcel/fidelity/activity/fragment/Launcher.kt +++ b/app/src/main/java/net/helcel/fidelity/activity/fragment/Launcher.kt @@ -49,6 +49,11 @@ class Launcher : Fragment() { startScanner() hideMenuAdd() } + binding.btnOpen.setOnClickListener { + startFileScanner() + hideMenuAdd() + } + binding.btnManual.setOnClickListener { startCreateEntry() @@ -96,6 +101,10 @@ class Launcher : Fragment() { startFragment(Scanner()) } + private fun startFileScanner() { + startFragment(FileScanner()) + } + private fun startCreateEntry() { startFragment(CreateEntry()) } diff --git a/app/src/main/java/net/helcel/fidelity/activity/fragment/Scanner.kt b/app/src/main/java/net/helcel/fidelity/activity/fragment/Scanner.kt index 3ab5af4..589ec57 100644 --- a/app/src/main/java/net/helcel/fidelity/activity/fragment/Scanner.kt +++ b/app/src/main/java/net/helcel/fidelity/activity/fragment/Scanner.kt @@ -2,25 +2,23 @@ package net.helcel.fidelity.activity.fragment import android.Manifest import android.content.ContentValues -import android.content.pm.PackageManager import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts import androidx.camera.core.CameraSelector import androidx.camera.core.Preview import androidx.camera.lifecycle.ProcessCameraProvider -import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import net.helcel.fidelity.R 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 -private const val CAMERA_PERMISSION_REQUEST_CODE = 1 - class Scanner : Fragment() { private lateinit var binding: FragScannerBinding @@ -28,6 +26,17 @@ class Scanner : Fragment() { private var code: String = "" private var fmt: String = "" + + private val resultPermissionRequest = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { + if (it) { + bindCameraUseCases() + } else { + parentFragmentManager.popBackStack() + ErrorToaster.noPermission(context) + } + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -37,11 +46,8 @@ class Scanner : Fragment() { binding.btnScanDone.setOnClickListener { startCreateEntry() } - when (hasCameraPermission()) { - true -> bindCameraUseCases() - else -> requestPermission() - } binding.btnScanDone.isEnabled = false + resultPermissionRequest.launch(Manifest.permission.CAMERA) return binding.root } @@ -55,26 +61,16 @@ class Scanner : Fragment() { .commit() } - private fun hasCameraPermission() = - ActivityCompat.checkSelfPermission( - requireContext(), - Manifest.permission.CAMERA - ) == PackageManager.PERMISSION_GRANTED - - private fun requestPermission() { - ActivityCompat.requestPermissions( - requireActivity(), - arrayOf(Manifest.permission.CAMERA), - CAMERA_PERMISSION_REQUEST_CODE - ) - ActivityCompat.OnRequestPermissionsResultCallback { c, p, i -> - require(c == CAMERA_PERMISSION_REQUEST_CODE) - require(p.contains(Manifest.permission.CAMERA)) - val el = i[p.indexOf(Manifest.permission.CAMERA)] - if (el != PackageManager.PERMISSION_GRANTED) { - startCreateEntry() - } + private fun scannerResult(code: String?, format: String?) { + if (!code.isNullOrEmpty() && !format.isNullOrEmpty()) { + this.code = code + this.fmt = format + } + val isDone = this.code.isNotEmpty() && this.fmt.isNotEmpty() + requireActivity().runOnUiThread { + binding.btnScanDone.isEnabled = isDone + binding.ScanActive.isEnabled = !isDone } } @@ -89,16 +85,8 @@ class Scanner : Fragment() { it.setSurfaceProvider(binding.cameraView.surfaceProvider) } val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA - val analysisUseCase = getAnalysisUseCase { code, format -> - if (!code.isNullOrEmpty() && !format.isNullOrEmpty()) { - this.code = code - this.fmt = format - } - val isDone = this.code.isNotEmpty() && this.fmt.isNotEmpty() - requireActivity().runOnUiThread { - binding.btnScanDone.isEnabled = isDone - binding.ScanActive.isEnabled = !isDone - } + val analysisUseCase = analysisUseCase { code, format -> + scannerResult(code, format) } try { cameraProvider.bindToLifecycle( diff --git a/app/src/main/java/net/helcel/fidelity/tools/BarcodeScanner.kt b/app/src/main/java/net/helcel/fidelity/tools/BarcodeScanner.kt index f356320..a981899 100644 --- a/app/src/main/java/net/helcel/fidelity/tools/BarcodeScanner.kt +++ b/app/src/main/java/net/helcel/fidelity/tools/BarcodeScanner.kt @@ -4,7 +4,6 @@ import android.graphics.Bitmap import androidx.annotation.OptIn import androidx.camera.core.ExperimentalGetImage import androidx.camera.core.ImageAnalysis -import androidx.camera.core.ImageProxy import com.google.zxing.BinaryBitmap import com.google.zxing.MultiFormatReader import com.google.zxing.NotFoundException @@ -15,14 +14,13 @@ import net.helcel.fidelity.tools.BarcodeFormatConverter.formatToString import java.util.concurrent.Executors +@OptIn(ExperimentalGetImage::class) object BarcodeScanner { - @OptIn(ExperimentalGetImage::class) - private fun processImageProxy( - imageProxy: ImageProxy, + private fun processImage( + bitmap: Bitmap, cb: (String?, String?) -> Unit ) { - val bitmap = imageProxy.toBitmap() // Convert ImageProxy to Bitmap val binaryBitmap = createBinaryBitmap(bitmap) val reader = MultiFormatReader() try { @@ -32,8 +30,6 @@ object BarcodeScanner { cb(null, null) } catch (e: ReaderException) { cb(null, null) - } finally { - imageProxy.close() } } @@ -45,13 +41,21 @@ object BarcodeScanner { return BinaryBitmap(HybridBinarizer(source)) } - fun getAnalysisUseCase(cb: (String?, String?) -> Unit): ImageAnalysis { + fun analysisUseCase(cb: (String?, String?) -> Unit): ImageAnalysis { val analysisUseCase = ImageAnalysis.Builder().build() analysisUseCase.setAnalyzer( Executors.newSingleThreadExecutor() ) { imageProxy -> - processImageProxy(imageProxy, cb) + val bitmap = imageProxy.toBitmap() + imageProxy.close() + bitmapUseCase(bitmap, cb) } return analysisUseCase } + + fun bitmapUseCase(bitmap: Bitmap, cb: (String?, String?) -> Unit) { + processImage(bitmap, cb) + } + + } \ No newline at end of file diff --git a/app/src/main/java/net/helcel/fidelity/tools/ErrorToaster.kt b/app/src/main/java/net/helcel/fidelity/tools/ErrorToaster.kt index 70a754f..4973cc7 100644 --- a/app/src/main/java/net/helcel/fidelity/tools/ErrorToaster.kt +++ b/app/src/main/java/net/helcel/fidelity/tools/ErrorToaster.kt @@ -20,4 +20,12 @@ object ErrorToaster { fun invalidFormat(activity: Context?) { 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) + } } diff --git a/app/src/main/res/drawable/open.xml b/app/src/main/res/drawable/open.xml new file mode 100644 index 0000000..9d82c42 --- /dev/null +++ b/app/src/main/res/drawable/open.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/app/src/main/res/layout/frag_launcher.xml b/app/src/main/res/layout/frag_launcher.xml index c23c101..30a1cae 100644 --- a/app/src/main/res/layout/frag_launcher.xml +++ b/app/src/main/res/layout/frag_launcher.xml @@ -56,6 +56,16 @@ app:maxImageSize="32dp" app:srcCompat="@drawable/camera" /> + + Code Format Save + Open CODE_39 CODE_93 diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt new file mode 100644 index 0000000..eb5b650 --- /dev/null +++ b/metadata/en-US/full_description.txt @@ -0,0 +1 @@ +

Keepass-Fidelity adds an interface to view/save barcodes (QR included) to Keepass through the plugin interface of the Keepass2Android app.


  • Launcher: view and launch recent entries (a per entry flag can disable this behaviour)
  • View: view entries from the history or queried from Keepass2Android
  • Create: add entries from the camera, an image of by filling out a form. The entry is then created in the Keepass2Android app
  • Data: 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).
\ No newline at end of file diff --git a/metadata/en-US/images/icon.png b/metadata/en-US/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..34087a08c74ac9011783d05007fdc5cd28e10b56 GIT binary patch literal 22132 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 literal 0 HcmV?d00001 diff --git a/.github/images/edit.jpg b/metadata/en-US/images/phoneScreenshots/edit.jpg similarity index 100% rename from .github/images/edit.jpg rename to metadata/en-US/images/phoneScreenshots/edit.jpg diff --git a/.github/images/launcher.jpg b/metadata/en-US/images/phoneScreenshots/launcher.jpg similarity index 100% rename from .github/images/launcher.jpg rename to metadata/en-US/images/phoneScreenshots/launcher.jpg diff --git a/.github/images/view.jpg b/metadata/en-US/images/phoneScreenshots/view.jpg similarity index 100% rename from .github/images/view.jpg rename to metadata/en-US/images/phoneScreenshots/view.jpg diff --git a/metadata/en-US/short_description.txt b/metadata/en-US/short_description.txt new file mode 100644 index 0000000..408c2f1 --- /dev/null +++ b/metadata/en-US/short_description.txt @@ -0,0 +1 @@ +Fidelity (Membership/Loyalty) Card plugin for Keepass2Android \ No newline at end of file