diff --git a/app/src/main/java/de/softwareapp_hb/privateqrscanner/MainActivity.kt b/app/src/main/java/de/softwareapp_hb/privateqrscanner/MainActivity.kt index 4dbb5f1..a8eb3ef 100644 --- a/app/src/main/java/de/softwareapp_hb/privateqrscanner/MainActivity.kt +++ b/app/src/main/java/de/softwareapp_hb/privateqrscanner/MainActivity.kt @@ -2,7 +2,9 @@ package de.softwareapp_hb.privateqrscanner import android.os.Bundle import androidx.activity.ComponentActivity +import androidx.activity.compose.LocalActivityResultRegistryOwner import androidx.activity.compose.setContent +import androidx.activity.result.ActivityResultRegistryOwner import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -23,13 +25,16 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) val container = (application as CleanScannerApp).appContainer setContent { - PrivateQrLocalizedContent(container) + PrivateQrLocalizedContent(container, activityResultRegistryOwner = this) } } } @Composable -private fun PrivateQrLocalizedContent(container: AppContainer) { +private fun PrivateQrLocalizedContent( + container: AppContainer, + activityResultRegistryOwner: ActivityResultRegistryOwner +) { val baseContext = LocalContext.current val localeOptions = remember(baseContext.applicationContext) { AppLocaleCatalog.load(baseContext.applicationContext) @@ -48,6 +53,7 @@ private fun PrivateQrLocalizedContent(container: AppContainer) { } CompositionLocalProvider( + LocalActivityResultRegistryOwner provides activityResultRegistryOwner, LocalContext provides localizedContext, LocalConfiguration provides localizedContext.resources.configuration ) { diff --git a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/HistoryScreen.kt b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/HistoryScreen.kt index 9c64447..2836bfe 100644 --- a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/HistoryScreen.kt +++ b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/HistoryScreen.kt @@ -1,5 +1,6 @@ package de.softwareapp_hb.privateqrscanner.ui.screens +import android.content.Context import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -107,7 +108,7 @@ fun HistoryScreen( val detailIsBase64 = detail.isBase64Encoded() AlertDialog( onDismissRequest = { selectedItem.value = null }, - title = { Text(text = detail.type) }, + title = { Text(text = detail.localizedDisplayType(context)) }, text = { if (detailIsBase64) { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { @@ -239,7 +240,7 @@ fun HistoryScreen( text = stringResource(R.string.share_txt), enabled = history.isNotEmpty(), onClick = { - val exportText = HistoryExportFormatter.formatText(history) + val exportText = HistoryExportFormatter.formatText(localizedHistory(context, history)) Intents.shareContent(context, exportText, "text/plain") } ) @@ -247,7 +248,7 @@ fun HistoryScreen( text = stringResource(R.string.share_csv), enabled = history.isNotEmpty(), onClick = { - val exportCsv = HistoryExportFormatter.formatCsv(history) + val exportCsv = HistoryExportFormatter.formatCsv(localizedHistory(context, history)) Intents.shareContent(context, exportCsv, "text/csv") } ) @@ -255,7 +256,7 @@ fun HistoryScreen( text = stringResource(R.string.share_json), enabled = history.isNotEmpty(), onClick = { - val exportJson = HistoryExportFormatter.formatJson(history) + val exportJson = HistoryExportFormatter.formatJson(localizedHistory(context, history)) Intents.shareContent(context, exportJson, "application/json") } ) @@ -399,21 +400,33 @@ private fun LocalControlsCard( text = stringResource(R.string.share_txt), enabled = history.isNotEmpty(), onClick = { - Intents.shareContent(context, HistoryExportFormatter.formatText(history), "text/plain") + Intents.shareContent( + context, + HistoryExportFormatter.formatText(localizedHistory(context, history)), + "text/plain" + ) } ) ExportButton( text = stringResource(R.string.share_csv), enabled = history.isNotEmpty(), onClick = { - Intents.shareContent(context, HistoryExportFormatter.formatCsv(history), "text/csv") + Intents.shareContent( + context, + HistoryExportFormatter.formatCsv(localizedHistory(context, history)), + "text/csv" + ) } ) ExportButton( text = stringResource(R.string.share_json), enabled = history.isNotEmpty(), onClick = { - Intents.shareContent(context, HistoryExportFormatter.formatJson(history), "application/json") + Intents.shareContent( + context, + HistoryExportFormatter.formatJson(localizedHistory(context, history)), + "application/json" + ) } ) } @@ -588,6 +601,7 @@ private fun HistoryRow( onDelete: (Long) -> Unit, onOpenDetails: () -> Unit ) { + val context = LocalContext.current val dismissState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == SwipeToDismissBoxValue.EndToStart || it == SwipeToDismissBoxValue.StartToEnd) { @@ -638,7 +652,7 @@ private fun HistoryRow( verticalAlignment = Alignment.CenterVertically ) { Text( - text = item.type, + text = item.localizedDisplayType(context), color = PrivateQrColors.TextPrimary, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.ExtraBold @@ -678,6 +692,12 @@ private fun iconForType(type: String): ImageVector { } } +private fun localizedHistory(context: Context, history: List): List { + return history.map { item -> + item.copy(type = item.localizedDisplayType(context)) + } +} + private fun ScanRecord.isBase64Encoded(): Boolean { return type.contains("base64", ignoreCase = true) } diff --git a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/LocalizedScanType.kt b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/LocalizedScanType.kt new file mode 100644 index 0000000..b9d9f83 --- /dev/null +++ b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/LocalizedScanType.kt @@ -0,0 +1,95 @@ +package de.softwareapp_hb.privateqrscanner.ui.screens + +import android.content.Context +import androidx.annotation.StringRes +import de.softwareapp_hb.privateqrscanner.R +import de.softwareapp_hb.privateqrscanner.domain.ScanRecord +import de.softwareapp_hb.privateqrscanner.domain.ScanResult + +private const val DUPLICATE_TICKET_PREFIX = "Duplicate ticket (" +private const val UNREGISTERED_TICKET_PREFIX = "Unregistered ticket (" +private val base64SuffixRegex = Regex("""\s*\(Base64\)\s*$""", RegexOption.IGNORE_CASE) + +internal fun ScanResult.localizedDisplayType(context: Context): String { + return localizedScanType( + context = context, + type = type, + isBase64Encoded = isBase64Encoded + ) +} + +internal fun ScanRecord.localizedDisplayType(context: Context): String { + return localizedStoredScanType(context, type) +} + +private fun localizedStoredScanType(context: Context, rawType: String): String { + val trimmed = rawType.trim() + extractWrappedType(trimmed, DUPLICATE_TICKET_PREFIX)?.let { innerType -> + return context.getString( + R.string.scan_type_duplicate_ticket, + localizedStoredScanType(context, innerType) + ) + } + extractWrappedType(trimmed, UNREGISTERED_TICKET_PREFIX)?.let { innerType -> + return context.getString( + R.string.scan_type_unregistered_ticket, + localizedStoredScanType(context, innerType) + ) + } + if (base64SuffixRegex.containsMatchIn(trimmed)) { + val innerType = base64SuffixRegex.replace(trimmed, "").trim() + return context.getString( + R.string.scan_type_base64_suffix, + localizedCanonicalScanType(context, innerType) + ) + } + return localizedCanonicalScanType(context, trimmed) +} + +private fun localizedScanType( + context: Context, + type: String, + isBase64Encoded: Boolean +): String { + val baseType = localizedCanonicalScanType(context, type) + return if (isBase64Encoded && !type.contains("base64", ignoreCase = true)) { + context.getString(R.string.scan_type_base64_suffix, baseType) + } else { + baseType + } +} + +private fun localizedCanonicalScanType(context: Context, type: String): String { + val stringRes = scanTypeStringRes(type) + return if (stringRes != null) { + context.getString(stringRes) + } else { + type.ifBlank { context.getString(R.string.scan_type_unknown) } + } +} + +private fun extractWrappedType(type: String, prefix: String): String? { + return if (type.startsWith(prefix, ignoreCase = true) && type.endsWith(")")) { + type.substring(prefix.length, type.length - 1) + } else { + null + } +} + +@StringRes +private fun scanTypeStringRes(type: String): Int? = when (type.trim().lowercase()) { + "contact" -> R.string.scan_type_contact + "url" -> R.string.scan_type_url + "wifi", "wi-fi" -> R.string.scan_type_wifi + "phone" -> R.string.scan_type_phone + "sms" -> R.string.scan_type_sms + "email", "e-mail" -> R.string.scan_type_email + "calendar" -> R.string.scan_type_calendar + "isbn" -> R.string.scan_type_isbn + "product" -> R.string.scan_type_product + "text" -> R.string.scan_type_text + "geo" -> R.string.scan_type_geo + "driver license", "driver licence" -> R.string.scan_type_driver_license + "unknown" -> R.string.scan_type_unknown + else -> null +} diff --git a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerGalleryPreviewDialog.kt b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerGalleryPreviewDialog.kt index 3542cee..3b6b52f 100644 --- a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerGalleryPreviewDialog.kt +++ b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerGalleryPreviewDialog.kt @@ -394,7 +394,7 @@ internal fun GalleryScanPreviewDialog( } Column(modifier = Modifier.weight(1f)) { Text( - text = candidate.result.displayType, + text = candidate.result.localizedDisplayType(context), color = PrivateQrColors.TextPrimary, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.ExtraBold diff --git a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerOverlayComponents.kt b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerOverlayComponents.kt index a696814..279d3cb 100644 --- a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerOverlayComponents.kt +++ b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerOverlayComponents.kt @@ -1,5 +1,6 @@ package de.softwareapp_hb.privateqrscanner.ui.screens +import android.content.Context import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -115,7 +116,7 @@ internal fun BatchResultsPanel( ) if (allowShare) { TextButton( - onClick = { Intents.shareText(context, buildBatchExport(results)) }, + onClick = { Intents.shareText(context, buildBatchExport(context, results)) }, enabled = results.isNotEmpty(), colors = ButtonDefaults.textButtonColors( containerColor = PrivateQrColors.Mint, @@ -143,7 +144,7 @@ internal fun BatchResultsPanel( ) { Column(modifier = Modifier.weight(1f)) { Text( - text = "${item.result.displayType}: $contentText", + text = "${item.result.localizedDisplayType(context)}: $contentText", color = Color.White.copy(alpha = 0.92f), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold, @@ -218,12 +219,12 @@ internal fun BatchResultsPanel( } } -private fun buildBatchExport(results: List): String { +private fun buildBatchExport(context: Context, results: List): String { if (results.isEmpty()) return "" val formatter = DateFormat.getDateTimeInstance() return results.joinToString(separator = "\n\n") { item -> val encoding = if (item.result.isBase64Encoded) "\nEncoding: Base64" else "" - "${formatter.format(Date(item.timestamp))}\n${item.result.displayType}$encoding\n${item.result.content}" + "${formatter.format(Date(item.timestamp))}\n${item.result.localizedDisplayType(context)}$encoding\n${item.result.content}" } } diff --git a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerResultCards.kt b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerResultCards.kt index 639a7d8..da0e8c9 100644 --- a/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerResultCards.kt +++ b/app/src/main/java/de/softwareapp_hb/privateqrscanner/ui/screens/ScannerResultCards.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow @@ -46,6 +47,7 @@ internal fun ResultVisualCard( onOpenUrl: ((String) -> Unit)? = null, modifier: Modifier = Modifier ) { + val context = LocalContext.current val contact = remember(result) { if (result.isBase64Encoded) null else ScanContentParsers.parseContact(result.content) } @@ -79,7 +81,7 @@ internal fun ResultVisualCard( tint = PrivateQrColors.Teal700 ) Text( - text = "Wi-Fi", + text = result.localizedDisplayType(context), style = MaterialTheme.typography.headlineSmall ) } @@ -90,7 +92,7 @@ internal fun ResultVisualCard( verticalAlignment = Alignment.CenterVertically ) { Text( - text = result.displayType, + text = result.localizedDisplayType(context), style = MaterialTheme.typography.headlineSmall, color = PrivateQrColors.TextPrimary ) @@ -215,7 +217,8 @@ private fun ContactVisualCard( ContactCardTemplate.Playful -> Color(0xFF55657B) ContactCardTemplate.Minimal -> Color(0xFF475569) } - val name = contact?.fullName ?: "Contact" + val fallbackName = stringResource(R.string.scan_type_contact) + val name = contact?.fullName ?: fallbackName val subtitle = listOfNotNull(contact?.title, contact?.organization).distinct().joinToString(" • ") val initials = remember(name) { initialsFromName(name) } diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index ac02315..5e2ba04 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -46,9 +46,25 @@ تم رصد رمز. ثبّت الجهاز أو اقترب. تم اكتشاف رمز قابل للقراءة. مشاركة السجل - TXT + نص CSV JSON + جهة اتصال + رابط + Wi-Fi + هاتف + SMS + بريد إلكتروني + تقويم + ISBN + منتج + نص + موقع + رخصة قيادة + غير معروف + %1$s (Base64) + تذكرة مكررة (%1$s) + تذكرة غير مسجلة (%1$s) يبقى السجل الاختياري على جهازك راجع عمليات المسح السابقة محليًا ابحث أو صدّر أو احذف عمليات المسح المحفوظة متى شئت. diff --git a/app/src/main/res/values-b+pt+BR/strings.xml b/app/src/main/res/values-b+pt+BR/strings.xml index e150338..0bac099 100644 --- a/app/src/main/res/values-b+pt+BR/strings.xml +++ b/app/src/main/res/values-b+pt+BR/strings.xml @@ -46,9 +46,25 @@ Código encontrado. Mantenha firme ou aproxime-se. Código legível detectado. Compartilhar histórico - TXT + Texto CSV JSON + Contato + Link + Wi-Fi + Telefone + SMS + E-mail + Calendário + ISBN + Produto + Texto + Localização + Carteira de motorista + Desconhecido + %1$s (Base64) + Ingresso duplicado (%1$s) + Ingresso não registrado (%1$s) O histórico opcional fica no seu dispositivo Revise leituras anteriores localmente Pesquise, exporte ou exclua leituras salvas quando quiser. diff --git a/app/src/main/res/values-b+pt+PT/strings.xml b/app/src/main/res/values-b+pt+PT/strings.xml index 1da2f06..709bfc7 100644 --- a/app/src/main/res/values-b+pt+PT/strings.xml +++ b/app/src/main/res/values-b+pt+PT/strings.xml @@ -46,9 +46,25 @@ Código detetado. Mantenha estável ou aproxime-se. Código legível detetado. Partilhar histórico - TXT + Texto CSV JSON + Contacto + Ligação + Wi-Fi + Telefone + SMS + E-mail + Calendário + ISBN + Produto + Texto + Localização + Carta de condução + Desconhecido + %1$s (Base64) + Bilhete duplicado (%1$s) + Bilhete não registado (%1$s) O histórico opcional fica no seu dispositivo Reveja digitalizações anteriores localmente Pesquise, exporte ou elimine digitalizações guardadas quando quiser. diff --git a/app/src/main/res/values-b+zh+Hans/strings.xml b/app/src/main/res/values-b+zh+Hans/strings.xml index 7e7f53b..0f0da5c 100644 --- a/app/src/main/res/values-b+zh+Hans/strings.xml +++ b/app/src/main/res/values-b+zh+Hans/strings.xml @@ -46,9 +46,25 @@ 发现代码。请保持稳定或靠近一些。 检测到可读取的代码。 分享历史记录 - TXT + 文本 CSV JSON + 联系人 + 链接 + Wi-Fi + 电话 + SMS + 电子邮件 + 日历 + ISBN + 产品 + 文本 + 位置 + 驾驶证 + 未知 + %1$s (Base64) + 重复票券(%1$s) + 未注册票券(%1$s) 可选历史记录保留在你的设备上 在本地查看过去的扫描 随时搜索、导出或删除已保存的扫描。 diff --git a/app/src/main/res/values-b+zh+Hant/strings.xml b/app/src/main/res/values-b+zh+Hant/strings.xml index f0c3f87..e6c9fb0 100644 --- a/app/src/main/res/values-b+zh+Hant/strings.xml +++ b/app/src/main/res/values-b+zh+Hant/strings.xml @@ -46,9 +46,25 @@ 發現代碼。請保持穩定或靠近一些。 偵測到可讀取的代碼。 分享記錄 - TXT + 文字 CSV JSON + 聯絡人 + 連結 + Wi-Fi + 電話 + SMS + 電子郵件 + 日曆 + ISBN + 產品 + 文字 + 位置 + 駕駛執照 + 未知 + %1$s (Base64) + 重複票券(%1$s) + 未註冊票券(%1$s) 可選記錄會保留在你的裝置上 在本機查看過去的掃描 隨時搜尋、匯出或刪除已儲存的掃描。 diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 876ec3e..b92e165 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -46,9 +46,25 @@ Code erkannt. Ruhig halten oder näher rangehen. Lesbarer Code erkannt. Historie teilen - TXT + Text CSV JSON + Kontakt + Link + WLAN + Telefon + SMS + E-Mail + Kalender + ISBN + Produkt + Text + Standort + Führerschein + Unbekannt + %1$s (Base64) + Doppeltes Ticket (%1$s) + Nicht registriertes Ticket (%1$s) Optionale Historie bleibt auf deinem Gerät Vergangene Scans lokal prüfen Gespeicherte Scans jederzeit suchen, exportieren oder löschen. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 545d35c..686f8ea 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -46,9 +46,25 @@ Código detectado. Mantén el dispositivo estable o acércate. Código legible detectado. Compartir historial - TXT + Texto CSV JSON + Contacto + Enlace + Wi-Fi + Teléfono + SMS + Correo electrónico + Calendario + ISBN + Producto + Texto + Ubicación + Permiso de conducir + Desconocido + %1$s (Base64) + Ticket duplicado (%1$s) + Ticket no registrado (%1$s) El historial opcional permanece en tu dispositivo Revisa escaneos anteriores localmente Busca, exporta o elimina escaneos guardados cuando quieras. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9a235c6..4013b03 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -46,9 +46,25 @@ Code repéré. Restez stable ou rapprochez-vous. Code lisible détecté. Partager l’historique - TXT + Texte CSV JSON + Contact + Lien + Wi-Fi + Téléphone + SMS + E-mail + Calendrier + ISBN + Produit + Texte + Emplacement + Permis de conduire + Inconnu + %1$s (Base64) + Ticket en double (%1$s) + Ticket non enregistré (%1$s) L’historique facultatif reste sur votre appareil Consulter les scans passés localement Recherchez, exportez ou supprimez les scans enregistrés quand vous le souhaitez. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 33d0cac..a803614 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -46,9 +46,25 @@ Codice individuato. Tieni fermo o avvicinati. Codice leggibile rilevato. Condividi cronologia - TXT + Testo CSV JSON + Contatto + Link + Wi-Fi + Telefono + SMS + Email + Calendario + ISBN + Prodotto + Testo + Posizione + Patente di guida + Sconosciuto + %1$s (Base64) + Ticket duplicato (%1$s) + Ticket non registrato (%1$s) La cronologia opzionale resta sul tuo dispositivo Rivedi localmente le scansioni passate Cerca, esporta o elimina le scansioni salvate quando vuoi. diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 3179f9a..5866102 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -46,9 +46,25 @@ コードを検出しました。端末を安定させるか、近づけてください。 読み取り可能なコードを検出しました。 履歴を共有 - TXT + テキスト CSV JSON + 連絡先 + リンク + Wi-Fi + 電話 + SMS + メール + カレンダー + ISBN + 製品 + テキスト + 位置情報 + 運転免許証 + 不明 + %1$s (Base64) + 重複チケット(%1$s) + 未登録チケット(%1$s) 任意の履歴は端末内に残ります 過去のスキャンをローカルで確認 保存したスキャンをいつでも検索、エクスポート、削除できます。 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 559eea9..920c0c3 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -46,9 +46,25 @@ 코드를 찾았습니다. 기기를 고정하거나 더 가까이 이동하세요. 읽을 수 있는 코드가 감지되었습니다. 기록 공유 - TXT + 텍스트 CSV JSON + 연락처 + 링크 + Wi-Fi + 전화 + SMS + 이메일 + 캘린더 + ISBN + 제품 + 텍스트 + 위치 + 운전면허증 + 알 수 없음 + %1$s (Base64) + 중복 티켓(%1$s) + 등록되지 않은 티켓(%1$s) 선택적 기록은 기기에 남습니다 지난 스캔을 로컬에서 확인 저장된 스캔을 언제든 검색, 내보내기 또는 삭제할 수 있습니다. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd118f6..0a7e3e5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -46,9 +46,25 @@ Code spotted. Hold steady or move closer. Readable code detected. Share history - TXT + Text CSV JSON + Contact + Link + Wi-Fi + Phone + SMS + Email + Calendar + ISBN + Product + Text + Location + Driver license + Unknown + %1$s (Base64) + Duplicate ticket (%1$s) + Unregistered ticket (%1$s) Optional history stays on your device Review past scans locally Search, export, or delete saved scans whenever you choose.