From d9a03c7131defe3a775c6290c7ea2accd3fbcdbb Mon Sep 17 00:00:00 2001 From: Pierre-Yves Nicolas <6371790+pynicolas@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:40:42 +0200 Subject: [PATCH] CameraScreen: set up a Preview to make it easier to work on the layout --- .../java/org/mydomain/myscan/view/Camera.kt | 109 +++++++++++++----- 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/org/mydomain/myscan/view/Camera.kt b/app/src/main/java/org/mydomain/myscan/view/Camera.kt index 75318b0..e0be20a 100644 --- a/app/src/main/java/org/mydomain/myscan/view/Camera.kt +++ b/app/src/main/java/org/mydomain/myscan/view/Camera.kt @@ -69,7 +69,6 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat @@ -82,6 +81,7 @@ import org.mydomain.myscan.LiveAnalysisState import org.mydomain.myscan.MainViewModel import org.mydomain.myscan.Point import org.mydomain.myscan.scaledTo +import org.mydomain.myscan.ui.theme.MyScanTheme import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -99,7 +99,6 @@ fun CameraScreen( val showPageDialog = rememberSaveable { mutableStateOf(false) } val isProcessing = rememberSaveable { mutableStateOf(false) } val pageToValidate by viewModel.pageToValidate.collectAsStateWithLifecycle() - val pageCount = viewModel.pageCount() val context = LocalContext.current val requestPermissionLauncher = rememberLauncherForActivityResult( @@ -122,32 +121,32 @@ fun CameraScreen( } } - Box(modifier = modifier.fillMaxSize()) { - CameraPreviewWithOverlay(onImageAnalyzed, captureController, liveAnalysisState) - MessageBox(liveAnalysisState.inferenceTime) - CaptureButton( - onClick = { - showPageDialog.value = true - isProcessing.value = true - captureController.takePicture( - onImageCaptured = { imageProxy -> - if (imageProxy != null) { - viewModel.processCapturedImageThen(imageProxy) { - isProcessing.value = false - } - } else { - Log.e("MyScan", "Error during image capture") + CameraScreenContent( + modifier, + cameraPreview = { + CameraPreview( + onImageAnalyzed = onImageAnalyzed, + captureController = captureController + ) }, + pageCount = viewModel.pageCount(), + liveAnalysisState, + onCapture = { + showPageDialog.value = true + isProcessing.value = true + captureController.takePicture( + onImageCaptured = { imageProxy -> + if (imageProxy != null) { + viewModel.processCapturedImageThen(imageProxy) { + isProcessing.value = false } + } else { + Log.e("MyScan", "Error during image capture") } - ) - }, - modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 96.dp) - ) - CameraScreenFooter( - pageCount = pageCount, - onFinalizePressed = onFinalizePressed, - modifier = Modifier.align(Alignment.BottomCenter)) - } + } + ) + }, + onFinalizePressed = onFinalizePressed + ) if (showPageDialog.value) { PageValidationDialog( @@ -167,6 +166,33 @@ fun CameraScreen( } } +@Composable +private fun CameraScreenContent( + modifier: Modifier, + cameraPreview: @Composable () -> Unit, + pageCount: Int, + liveAnalysisState: LiveAnalysisState, + onCapture: () -> Unit, + onFinalizePressed: () -> Unit +) { + Box(modifier = modifier.fillMaxSize()) { + CameraPreviewWithOverlay(cameraPreview, liveAnalysisState) + MessageBox(liveAnalysisState.inferenceTime) + + CaptureButton( + onClick = onCapture, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 96.dp) + ) + CameraScreenFooter( + pageCount = pageCount, + onFinalizePressed = onFinalizePressed, + modifier = Modifier.align(Alignment.BottomCenter) + ) + } +} + @Composable fun CaptureButton(onClick: () -> Unit, modifier: Modifier) { val color = MaterialTheme.colorScheme.primary @@ -199,8 +225,7 @@ fun CaptureButton(onClick: () -> Unit, modifier: Modifier) { @Composable private fun CameraPreviewWithOverlay( - onImageAnalyzed: (ImageProxy) -> Unit, - captureController: CameraCaptureController, + cameraPreview: @Composable () -> Unit, liveAnalysisState: LiveAnalysisState ) { val width = LocalConfiguration.current.screenWidthDp @@ -210,10 +235,7 @@ private fun CameraPreviewWithOverlay( .width(width.dp) .height(height.dp) ) { - CameraPreview( - onImageAnalyzed = onImageAnalyzed, - captureController = captureController - ) + cameraPreview() AnalysisOverlay(liveAnalysisState) } } @@ -405,3 +427,26 @@ fun CameraScreenFooter( } } } + +@androidx.compose.ui.tooling.preview.Preview(showBackground = true) +@Composable +fun CameraScreenPreview() { + MyScanTheme { + CameraScreenContent( + modifier = Modifier, + cameraPreview = { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.DarkGray), + contentAlignment = Alignment.Center + ) { + Text("Camera Preview", color = Color.White) + } + }, + pageCount = 3, + liveAnalysisState = LiveAnalysisState(), + onCapture = {}, + onFinalizePressed = {}) + } +}