mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 20:45:20 +00:00
Replace AndroidView with CameraXViewfinder for camera preview
This commit is contained in:
@@ -98,7 +98,7 @@ dependencies {
|
|||||||
// CameraX
|
// CameraX
|
||||||
implementation(libs.androidx.camera.camera2)
|
implementation(libs.androidx.camera.camera2)
|
||||||
implementation(libs.androidx.camera.lifecycle)
|
implementation(libs.androidx.camera.lifecycle)
|
||||||
implementation(libs.androidx.camera.view)
|
implementation(libs.androidx.camera.compose)
|
||||||
|
|
||||||
// Cryptography
|
// Cryptography
|
||||||
implementation(libs.bundles.cryptography)
|
implementation(libs.bundles.cryptography)
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import android.graphics.Bitmap
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.camera.compose.CameraXViewfinder
|
||||||
import androidx.camera.core.CameraSelector
|
import androidx.camera.core.CameraSelector
|
||||||
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 androidx.camera.core.Preview
|
import androidx.camera.core.Preview
|
||||||
|
import androidx.camera.core.SurfaceRequest
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
import androidx.camera.view.PreviewView
|
import androidx.camera.viewfinder.core.ImplementationMode
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
@@ -41,6 +43,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -59,7 +62,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.graphics.createBitmap
|
import androidx.core.graphics.createBitmap
|
||||||
import androidx.core.graphics.set
|
import androidx.core.graphics.set
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
@@ -73,6 +76,7 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions
|
|||||||
import com.google.mlkit.vision.barcode.BarcodeScanning
|
import com.google.mlkit.vision.barcode.BarcodeScanning
|
||||||
import com.google.mlkit.vision.barcode.common.Barcode
|
import com.google.mlkit.vision.barcode.common.Barcode
|
||||||
import com.google.mlkit.vision.common.InputImage
|
import com.google.mlkit.vision.common.InputImage
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
import com.google.zxing.common.BitMatrix
|
import com.google.zxing.common.BitMatrix
|
||||||
import com.google.zxing.qrcode.QRCodeWriter
|
import com.google.zxing.qrcode.QRCodeWriter
|
||||||
@@ -358,7 +362,8 @@ private fun QRScannerPanel(
|
|||||||
var lastValid by remember { mutableStateOf<String?>(null) }
|
var lastValid by remember { mutableStateOf<String?>(null) }
|
||||||
val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
|
val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
|
||||||
val cameraExecutor: ExecutorService = remember { Executors.newSingleThreadExecutor() }
|
val cameraExecutor: ExecutorService = remember { Executors.newSingleThreadExecutor() }
|
||||||
val barcodeView = remember { PreviewView(context) }
|
val surfaceRequests = remember { MutableStateFlow<SurfaceRequest?>(null) }
|
||||||
|
val surfaceRequest by surfaceRequests.collectAsState(initial = null)
|
||||||
val mainHandler = remember { Handler(Looper.getMainLooper()) }
|
val mainHandler = remember { Handler(Looper.getMainLooper()) }
|
||||||
|
|
||||||
val onCodeState = rememberUpdatedState(onScan)
|
val onCodeState = rememberUpdatedState(onScan)
|
||||||
@@ -373,19 +378,24 @@ private fun QRScannerPanel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(permissionState.status.isGranted) {
|
DisposableEffect(permissionState.status.isGranted) {
|
||||||
|
var cameraProvider: ProcessCameraProvider? = null
|
||||||
if (permissionState.status.isGranted) {
|
if (permissionState.status.isGranted) {
|
||||||
val cameraProvider = cameraProviderFuture.get()
|
val executor = ContextCompat.getMainExecutor(context)
|
||||||
|
cameraProviderFuture.addListener(
|
||||||
|
{
|
||||||
|
val provider = cameraProviderFuture.get()
|
||||||
|
cameraProvider = provider
|
||||||
val preview = Preview.Builder()
|
val preview = Preview.Builder()
|
||||||
.build()
|
.build()
|
||||||
.also { it.surfaceProvider = barcodeView.surfaceProvider }
|
.also { it.setSurfaceProvider { request -> surfaceRequests.value = request } }
|
||||||
val analysis = ImageAnalysis.Builder()
|
val analysis = ImageAnalysis.Builder()
|
||||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||||
.build()
|
.build()
|
||||||
.also { it.setAnalyzer(cameraExecutor, analyzer) }
|
.also { it.setAnalyzer(cameraExecutor, analyzer) }
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
cameraProvider.unbindAll()
|
provider.unbindAll()
|
||||||
cameraProvider.bindToLifecycle(
|
provider.bindToLifecycle(
|
||||||
lifecycleOwner,
|
lifecycleOwner,
|
||||||
CameraSelector.DEFAULT_BACK_CAMERA,
|
CameraSelector.DEFAULT_BACK_CAMERA,
|
||||||
preview,
|
preview,
|
||||||
@@ -394,10 +404,14 @@ private fun QRScannerPanel(
|
|||||||
}.onFailure {
|
}.onFailure {
|
||||||
Log.w("VerificationSheet", "Failed to bind camera: ${it.message}")
|
Log.w("VerificationSheet", "Failed to bind camera: ${it.message}")
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
executor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDispose {
|
onDispose {
|
||||||
runCatching { cameraProviderFuture.get().unbindAll() }
|
surfaceRequests.value = null
|
||||||
|
runCatching { cameraProvider?.unbindAll() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,12 +437,15 @@ private fun QRScannerPanel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (permissionState.status.isGranted) {
|
if (permissionState.status.isGranted) {
|
||||||
AndroidView(
|
surfaceRequest?.let { request ->
|
||||||
factory = { barcodeView },
|
CameraXViewfinder(
|
||||||
|
surfaceRequest = request,
|
||||||
|
implementationMode = ImplementationMode.EMBEDDED,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(220.dp)
|
.size(220.dp)
|
||||||
.clipToBounds()
|
.clipToBounds()
|
||||||
)
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.verify_camera_permission),
|
text = stringResource(R.string.verify_camera_permission),
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ zxing-core = { module = "com.google.zxing:core", version.ref = "zxing-core" }
|
|||||||
# CameraX / ML Kit
|
# CameraX / ML Kit
|
||||||
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }
|
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }
|
||||||
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camerax" }
|
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camerax" }
|
||||||
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }
|
androidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "camerax" }
|
||||||
mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlkit-barcode" }
|
mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlkit-barcode" }
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|||||||
Reference in New Issue
Block a user