diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 64532f5a..7acfac69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,6 +31,11 @@ android:windowSoftInputMode="adjustResize" tools:targetApi="33"> + + + if (isGranted) { + setupScanner() + } else { + Toast.makeText(this, "Camera permission denied.", Toast.LENGTH_SHORT).show() + sendResultAndFinish(null) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (hasCameraPermission()) { + setupScanner() + } else { + cameraPermissionLauncher.launch(Manifest.permission.CAMERA) + } + } + + private fun hasCameraPermission(): Boolean { + return checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED + } + + private fun setupScanner() { + barcodeView = DecoratedBarcodeView(this).apply { + barcodeView.decoderFactory = DefaultDecoderFactory(listOf(BarcodeFormat.QR_CODE)) + initializeFromIntent(intent) + decodeContinuous(object : BarcodeCallback { + override fun barcodeResult(result: BarcodeResult?) { + result?.text?.let { + sendResultAndFinish(it) + } + } + + override fun possibleResultPoints(resultPoints: MutableList?) {} + }) + } + + setContentView(barcodeView) + safeResumeScanner() + } + + private fun safeResumeScanner() { + try { + barcodeView.resume() + } catch (e: Exception) { + Log.e("QrScanner", "Camera resume failed: ${e.message}") + if (!hasFailedToResumeCamera) { + hasFailedToResumeCamera = true + Toast.makeText(this, "Camera is in use by another app.", Toast.LENGTH_LONG).show() + barcodeView.postDelayed({ + sendResultAndFinish(null) + }, 1500) + } + } + } + + override fun onResume() { + super.onResume() + if (::barcodeView.isInitialized && hasWindowFocus()) { + safeResumeScanner() + } + } + + override fun onPause() { + super.onPause() + if (::barcodeView.isInitialized) { + barcodeView.pause() + } + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + if (::barcodeView.isInitialized) { + if (hasFocus) safeResumeScanner() else barcodeView.pause() + } + } + + private fun sendResultAndFinish(result: String?) { + setResult(RESULT_OK, Intent().putExtra("qr_result", result)) + finish() + } +} diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/QrCodeScanner.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/QrCodeScanner.kt index 823f7522..d61f5302 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/QrCodeScanner.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/QrCodeScanner.kt @@ -1,37 +1,27 @@ package com.greenart7c3.nostrsigner.ui +import android.content.Intent import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.lifecycle.compose.LocalLifecycleOwner -import com.google.zxing.client.android.Intents -import com.journeyapps.barcodescanner.ScanContract -import com.journeyapps.barcodescanner.ScanOptions +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.platform.LocalContext +import com.greenart7c3.nostrsigner.QrCodeScannerActivity @Composable -fun SimpleQrCodeScanner(onScan: (String?) -> Unit) { - val lifecycleOwner = LocalLifecycleOwner.current +fun SimpleQrCodeScanner( + onScan: (String?) -> Unit, +) { + val context = LocalContext.current + val launcher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult(), + ) { result -> + val text = result.data?.getStringExtra("qr_result") + onScan(text) + } - val qrLauncher = - rememberLauncherForActivityResult(ScanContract()) { - if (it.contents != null) { - onScan(it.contents) - } else { - onScan(null) - } - } - - val scanOptions = - ScanOptions().apply { - setDesiredBarcodeFormats(ScanOptions.QR_CODE) - setPrompt("Point to the QR Code") - setBeepEnabled(false) - setOrientationLocked(false) - addExtra(Intents.Scan.SCAN_TYPE, Intents.Scan.MIXED_SCAN) - } - - DisposableEffect(lifecycleOwner) { - qrLauncher.launch(scanOptions) - onDispose { } + LaunchedEffect(Unit) { + val intent = Intent(context, QrCodeScannerActivity::class.java) + launcher.launch(intent) } }