UI: Camera Screen
Relevant source files
The following files were used as context for generating this wiki page:- app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraScreen.kt
- app/src/main/java/com/musagenius/ocrapp/presentation/viewmodel/CameraViewModel.kt
- app/src/main/java/com/musagenius/ocrapp/data/camera/CameraManager.kt
- app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraState.kt
- app/src/main/java/com/musagenius/ocrapp/MainActivity.kt
- app/src/main/AndroidManifest.xml
- app/src/main/java/com/musagenius/ocrapp/presentation/ui/editor/ImageEditorScreen.kt
The Camera Screen is the primary user interface for capturing images to be used for Optical Character Recognition (OCR). It serves as the main entry point for the app's core functionality. This screen is responsible for handling camera permissions, displaying a live camera preview, providing user controls for camera settings (flash, zoom, resolution), and managing the image capture process.
The screen is built entirely with Jetpack Compose and follows an MVVM architecture. It integrates with CameraX for camera operations and provides real-time feedback to the user, such as document edge detection and low-light warnings. Upon successful image capture, it navigates to the OCR Result Screen. If an image is selected from the gallery, it first navigates to the Image Editor Screen.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraScreen.kt, app/src/main/java/com/musagenius/ocrapp/MainActivity.kt:60-70
Architecture and State Management
The Camera Screen follows the Model-View-ViewModel (MVVM) pattern, separating UI logic from business logic. The state is managed reactively using Kotlin's StateFlow.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/viewmodel/CameraViewModel.kt, app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraScreen.kt
Component Architecture
The architecture consists of three main components:
CameraScreen.kt: A Jetpack Compose composable that observes the UI state from theCameraViewModeland renders the UI. It delegates all user actions to the ViewModel asCameraEvents.CameraViewModel.kt: The ViewModel holds theCameraUiState, processesCameraEvents from the UI, and interacts with theCameraManagerto perform camera operations.CameraManager.kt: A wrapper class that encapsulates all CameraX logic, such as starting the camera, capturing images, and managing camera settings. It is injected into theCameraViewModel.
The following diagram illustrates the relationship between these components.
UI State (CameraUiState)
The CameraUiState data class represents the complete state of the camera screen at any given time. The UI is a direct function of this state.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraState.kt:8-27
| Property | Type | Description |
|---|---|---|
isLoading | Boolean | True when the camera is being initialized. |
capturedImageUri | Uri? | The URI of the successfully captured and compressed image. |
error | String? | An error message to be displayed to the user. |
flashMode | FlashMode | The current flash mode (OFF, ON, AUTO). |
isProcessing | Boolean | True when an image is being captured and processed. |
zoomRatio | Float | The current camera zoom ratio. |
cameraFacing | CameraFacing | The current camera direction (BACK, FRONT). |
showGridOverlay | Boolean | Toggles the visibility of the grid overlay. |
showDocumentOverlay | Boolean | Toggles the visibility of the document detection overlay. |
documentCorners | DocumentCorners? | The coordinates of detected document corners. |
lightingCondition | LightingCondition | The detected lighting condition (GOOD, LOW, VERY_LOW). |
showLowLightWarning | Boolean | Toggles the visibility of the low light warning. |
resolution | CameraResolution | The current camera capture resolution. |
showResolutionDialog | Boolean | Toggles the visibility of the resolution selection dialog. |
UI Events (CameraEvent)
User interactions and internal callbacks are modeled as a sealed class named CameraEvent. These events are sent from the CameraScreen to the CameraViewModel for processing.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraState.kt:100-117
| Event | Description |
|---|---|
CaptureImage | Triggered when the user taps the capture button. |
ToggleFlash | Cycles through the available flash modes. |
PickFromGallery | Initiates picking an image from the device gallery. |
SetZoom | Fired during a pinch-to-zoom gesture to update the zoom ratio. |
TapToFocus | Fired on tap to trigger tap-to-focus. |
FlipCamera | Switches between the front and back cameras. |
ToggleGridOverlay | Toggles the grid overlay. |
ToggleDocumentOverlay | Toggles the document detection overlay. |
UpdateDocumentCorners | Internal event to update the state with new document corners from ImageAnalysis. |
UpdateLightingCondition | Internal event to update the state with the current lighting condition. |
SetResolution | Sets a new camera resolution and restarts the camera. |
Core Functionality
Camera Permission Handling
The app requires the android.permission.CAMERA to function. The permission flow is handled using the accompanist-permissions library.
- On screen launch, it checks if the permission is granted.
- If not granted, it checks if a rationale should be shown.
- If yes, a
PermissionRationaleDialogis displayed. - If no (first time or "Don't ask again"), the permission request is launched directly.
- If yes, a
- If the user denies the permission, a
PermissionDeniedDialogis shown with an option to open app settings. - If permission is not granted, a fallback UI is shown, allowing the user to either grant permission or pick an image from the gallery.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraScreen.kt:53-125, app/src/main/AndroidManifest.xml:12
This diagram shows the permission request flow.
Camera Startup and Preview
The camera is initialized asynchronously when the CameraScreen is composed and the camera permission is granted.
The following sequence diagram illustrates the camera startup process:
Image Capture and Processing
When the user taps the capture button, the CaptureImage event is sent to the CameraViewModel.
- The ViewModel sets the UI state to
isProcessing = true. - It checks for sufficient storage using
StorageManager. - It calls
cameraManager.captureImage(), which uses CameraX'sImageCapture.takePicture()to save the image to a file. - Upon receiving the raw image URI, the ViewModel uses
ImageCompressorto compress the image to a maximum size of 2048px and a quality of 85%. - The URI of the compressed image is updated in
CameraUiState. - A
LaunchedEffectinCameraScreenobserves this URI change and triggers navigation to the results screen.
This sequence diagram details the capture flow:
Navigation
The MainActivity defines the navigation graph for the application using NavHost. The CameraScreen is the start destination.
- When an image is captured,
onImageCapturedis called, which navigates toScreen.Results. The image URI is passed as a navigation argument. - When an image is selected from the gallery,
onGalleryImageSelectedis called, which navigates toScreen.ImageEditor. After editing and saving, the app navigates from the editor toScreen.Results.
UI Controls and Features
The CameraScreen is composed of several modular composables that provide a rich user experience.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraScreen.kt
| Component | File | Description |
|---|---|---|
CameraTopBar | CameraScreen.kt | Contains the back navigation icon and the flash toggle button (FlashOff, FlashOn, FlashAuto). |
CameraControls | CameraScreen.kt | Located at the bottom, it holds the main FloatingActionButton for capture and an IconButton to open the gallery. |
CameraTopControls | CameraScreen.kt | A column of FilledIconButtons for toggling resolution, flipping the camera, and toggling grid/document overlays. |
LowLightWarning | CameraScreen.kt | A Surface that appears at the top when lightingCondition is LOW or VERY_LOW, suggesting the user enable the flash. |
ResolutionSelectionDialog | CameraScreen.kt | An AlertDialog that allows the user to select the camera resolution from a list of CameraResolution enums (SD, HD, Full HD, 4K). |
DocumentOverlay | DocumentOverlay.kt | Draws lines on the camera preview connecting the points of the documentCorners provided by the CameraUiState. |
| Gestures | CameraScreen.kt | The CameraPreview container uses pointerInput modifiers to detect detectTransformGestures for pinch-to-zoom and detectTapGestures for tap-to-focus. |
Real-time Analysis (Document & Light Detection)
The CameraManager configures a CameraX ImageAnalysis use case. This use case receives frames from the camera in real-time and processes them without blocking the preview.
- The analyzer is set on the
ImageAnalysisinstance. - To avoid performance issues, an
AtomicBoolean(isProcessingFrame) ensures that only one frame is processed at a time. - The frame (
ImageProxy) is passed toDocumentEdgeDetectorandLowLightDetector. - The results (document corners and lighting condition) are sent back to the
CameraViewModelvia callbacks. - The ViewModel updates the
CameraUiState, which causes theDocumentOverlayandLowLightWarningUI to recompose with the new data.
Conclusion
The Camera Screen is a sophisticated and central component of the OCR application. It effectively uses Jetpack Compose and an MVVM architecture to create a reactive, state-driven UI. By encapsulating complex CameraX logic within a CameraManager and providing real-time feedback through ImageAnalysis, it offers a robust and user-friendly experience for the app's primary function: image capture for text recognition. The "shift-left" approach to accessibility, with semantic content descriptions and adequate touch targets, is evident throughout the implementation.
Sources: app/src/main/java/com/musagenius/ocrapp/presentation/ui/camera/CameraScreen.kt:38, 311, 331, 355