From 229244d8780223e2b991815777177f3d6e51fb6a Mon Sep 17 00:00:00 2001 From: Hadrian Burkhardt Date: Thu, 26 Feb 2026 05:29:45 +0100 Subject: [PATCH] wifi icon + qrcode stamps --- .../data/scanner/MlKitBarcodeAnalyzer.kt | 5 ++-- .../ui/screens/ScannerGalleryPreviewDialog.kt | 3 +- .../scanner/ui/screens/ScannerResultCards.kt | 28 ++++++++++++++++--- .../clean/scanner/ui/screens/ScannerScreen.kt | 5 ++-- .../com/clean/scanner/util/BarcodePayload.kt | 20 +++++++++++++ 5 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/clean/scanner/util/BarcodePayload.kt diff --git a/app/src/main/java/com/clean/scanner/data/scanner/MlKitBarcodeAnalyzer.kt b/app/src/main/java/com/clean/scanner/data/scanner/MlKitBarcodeAnalyzer.kt index 96cc60c..09c9916 100644 --- a/app/src/main/java/com/clean/scanner/data/scanner/MlKitBarcodeAnalyzer.kt +++ b/app/src/main/java/com/clean/scanner/data/scanner/MlKitBarcodeAnalyzer.kt @@ -5,6 +5,7 @@ import android.os.SystemClock import androidx.camera.core.ImageAnalysis import androidx.camera.core.ImageProxy import com.clean.scanner.domain.ScanResult +import com.clean.scanner.util.readablePayload import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.BarcodeScannerOptions import com.google.mlkit.vision.barcode.common.Barcode @@ -116,7 +117,7 @@ class MlKitBarcodeAnalyzer( scanner.process(image) .addOnSuccessListener { barcodes -> - val readable = barcodes.firstOrNull { !it.rawValue.isNullOrBlank() } + val readable = barcodes.firstOrNull { it.readablePayload() != null } val boxes = barcodes.mapNotNull { barcode -> val bounds = barcode.boundingBox ?: return@mapNotNull null val normalized = normalizeBoundingBox( @@ -164,7 +165,7 @@ class MlKitBarcodeAnalyzer( } onDetected( ScanResult( - content = readable.rawValue.orEmpty(), + content = readable.readablePayload().orEmpty(), type = readable.valueType.toHumanType() ), gatedReadableBox, diff --git a/app/src/main/java/com/clean/scanner/ui/screens/ScannerGalleryPreviewDialog.kt b/app/src/main/java/com/clean/scanner/ui/screens/ScannerGalleryPreviewDialog.kt index 15d45b7..640ae45 100644 --- a/app/src/main/java/com/clean/scanner/ui/screens/ScannerGalleryPreviewDialog.kt +++ b/app/src/main/java/com/clean/scanner/ui/screens/ScannerGalleryPreviewDialog.kt @@ -54,6 +54,7 @@ import com.clean.scanner.R import com.clean.scanner.data.scanner.DetectionBox import com.clean.scanner.data.scanner.DetectionPoint import com.clean.scanner.domain.ScanResult +import com.clean.scanner.util.readablePayload import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.BarcodeScanner import com.google.mlkit.vision.barcode.BarcodeScannerOptions @@ -174,7 +175,7 @@ internal fun GalleryScanPreviewDialog( } val live = barcodes.mapNotNull { barcode -> - val raw = barcode.rawValue?.takeIf { it.isNotBlank() } ?: return@mapNotNull null + val raw = barcode.readablePayload() ?: return@mapNotNull null val normalizedBox = barcode.boundingBox?.let { bounds -> val leftN = ((bounds.left + cropLeft) / imgW).coerceIn(0f, 1f) val topN = ((bounds.top + cropTop) / imgH).coerceIn(0f, 1f) diff --git a/app/src/main/java/com/clean/scanner/ui/screens/ScannerResultCards.kt b/app/src/main/java/com/clean/scanner/ui/screens/ScannerResultCards.kt index 4744b50..c590045 100644 --- a/app/src/main/java/com/clean/scanner/ui/screens/ScannerResultCards.kt +++ b/app/src/main/java/com/clean/scanner/ui/screens/ScannerResultCards.kt @@ -8,8 +8,11 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Wifi import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -57,10 +60,27 @@ internal fun ResultVisualCard( modifier = Modifier.padding(14.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - Text( - text = result.type, - style = MaterialTheme.typography.titleMedium - ) + if (result.type == "WiFi") { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Default.Wifi, + contentDescription = null, + tint = Color(0xFF1D4ED8) + ) + Text( + text = "Wi-Fi", + style = MaterialTheme.typography.titleMedium + ) + } + } else { + Text( + text = result.type, + style = MaterialTheme.typography.titleMedium + ) + } if (fields.isEmpty()) { Text( text = result.content, diff --git a/app/src/main/java/com/clean/scanner/ui/screens/ScannerScreen.kt b/app/src/main/java/com/clean/scanner/ui/screens/ScannerScreen.kt index 055f88c..4596607 100644 --- a/app/src/main/java/com/clean/scanner/ui/screens/ScannerScreen.kt +++ b/app/src/main/java/com/clean/scanner/ui/screens/ScannerScreen.kt @@ -80,6 +80,7 @@ import com.clean.scanner.util.ClipboardUtil import com.clean.scanner.util.Intents import com.clean.scanner.util.ScanContentParsers import com.clean.scanner.util.UrlRiskScorer +import com.clean.scanner.util.readablePayload import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.BarcodeScannerOptions import com.google.mlkit.vision.barcode.common.Barcode @@ -172,7 +173,7 @@ fun ScannerScreen( imageScanner.process(image) .addOnSuccessListener { barcodes -> val candidates = barcodes.mapNotNull { barcode -> - val raw = barcode.rawValue?.takeIf { it.isNotBlank() } ?: return@mapNotNull null + val raw = barcode.readablePayload() ?: return@mapNotNull null val normalizedBox = barcode.boundingBox?.let { bounds -> val corners = barcode.cornerPoints?.map { p -> DetectionPoint( @@ -469,7 +470,7 @@ fun ScannerScreen( .padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - if (parsedContact == null) { + if (parsedContact == null && lastResult.type != "WiFi") { Text(text = "${stringResource(R.string.content_type)}: ${lastResult.type}") } ResultVisualCard(result = lastResult) diff --git a/app/src/main/java/com/clean/scanner/util/BarcodePayload.kt b/app/src/main/java/com/clean/scanner/util/BarcodePayload.kt new file mode 100644 index 0000000..678b9b3 --- /dev/null +++ b/app/src/main/java/com/clean/scanner/util/BarcodePayload.kt @@ -0,0 +1,20 @@ +package com.clean.scanner.util + +import com.google.mlkit.vision.barcode.common.Barcode + +fun Barcode.readablePayload(): String? { + rawValue?.trim()?.takeIf { it.isNotBlank() }?.let { return it } + displayValue?.trim()?.takeIf { it.isNotBlank() }?.let { return it } + + val bytes = rawBytes?.takeIf { it.isNotEmpty() } ?: return null + val utf8 = bytes.toString(Charsets.UTF_8).trim() + if (utf8.isLikelyHumanReadable()) return utf8 + + return bytes.joinToString(separator = "") { byte -> "%02X".format(byte) } +} + +private fun String.isLikelyHumanReadable(): Boolean { + if (isBlank()) return false + val controlChars = count { it.isISOControl() && it != '\n' && it != '\r' && it != '\t' } + return controlChars == 0 +}