### Configure Awesome UI Camera Properties Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Example configuration for top actions, filters, and theme-related properties within the camera widget. ```dart splashColor: Colors.deepPurple, highlightColor: Colors.deepPurpleAccent.withValues(alpha: 0.5), onTap: onTap, child: child, ), ), ); }, ), ), // Top actions (flash, timer...) topActionsBuilder: (state) { return AwesomeTopActions(state: state); }, // default filter defaultFilter: AwesomeFilter.None, // list of photo filters (default to awesome filter) // put null or empty list for hiding filters availableFilters: awesomePresetFiltersList, ) ``` -------------------------------- ### Setup Camera Preview with Analysis Stream Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/image_format_conversions Uses a StreamController to pipe AnalysisImage data into a custom display widget within a CameraAwesomeBuilder. ```dart class CameraPage extends StatefulWidget { const CameraPage({super.key}); @override State createState() => _CameraPageState(); } class _CameraPageState extends State { // 1. final _imageStreamController = StreamController(); @override void dispose() { _imageStreamController.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // 2. body: CameraAwesomeBuilder.analysisOnly( sensorConfig: SensorConfig.single( sensor: Sensor.position(SensorPosition.front), aspectRatio: CameraAspectRatios.ratio_1_1, ), // 3. onImageForAnalysis: (img) async => _imageStreamController.add(img), imageAnalysisConfig: AnalysisConfig( androidOptions: const AndroidAnalysisOptions.yuv420( width: 150, ), maxFramesPerSecond: 30, ), builder: (state, previewSize, previewRect) { // 4. return CameraPreviewDisplayer( analysisImageStream: _imageStreamController.stream, ); }, ), ); } } ``` -------------------------------- ### Install MLKit Face Detection Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/detecting_faces Add the required dependency to your pubspec.yaml file. ```dart google_mlkit_face_detection: ^0.5.5 ``` -------------------------------- ### Customizing AwesomeTopActions Source: https://docs.page/Apparence-io/camera_awesome/widgets/layout Examples of how to use and customize the top actions row, including conditional rendering based on camera state. ```dart AwesomeTopActions( // CameraState is required state: state, // Add your own children children: [ MyFirstWidget(state: state), MySecondWidget(state: state), ], // Override default padding padding: const EdgeInsets.all(8), ) ``` ```dart AwesomeTopActions( // CameraState is required state: state, // Add your own children children: state is PhotoCameraState ? [ MyFirstWidget(state: state), MySecondWidget(state: state), ] : [ MyThirdWidget(state: state), ], // Override default padding padding: const EdgeInsets.all(8), ) ``` -------------------------------- ### Example of dependency conflict error Source: https://docs.page/Apparence-io/camera_awesome/getting_started/installing An example of an error message that might occur due to dependency conflicts. ```text java.lang.IncompatibleClassChangeError: Found interface com.google.android.gms.location.ActivityRecognitionClient, but class was expected ``` -------------------------------- ### Implement a Custom photoPathBuilder Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Define a custom path for saved photos using path_provider. This example handles both single and multiple sensor capture requests. ```dart SaveConfig.photoAndVideo( photoPathBuilder: (sensors) async { // 1. final Directory extDir = await getTemporaryDirectory(); final testDir = await Directory('${extDir.path}/camerawesome').create(recursive: true); // 2. if (sensors.length == 1) { final String filePath = '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg'; // 3. return SingleCaptureRequest(filePath, sensors.first); } else { // 4. return MultipleCaptureRequest( { for (final sensor in sensors) sensor: '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg', }, ); } }, // Other params ... ) ``` -------------------------------- ### Customize UI Layout with Builders Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Use topActionsBuilder, middleContentBuilder, and bottomActionsBuilder to define custom widgets for specific UI areas. The example demonstrates applying a custom theme and injecting specific widgets like filters and buttons. ```dart CameraAwesomeBuilder.awesome( // Other parameters ... // Set an AwesomeTheme that you might reuse in your UI theme: AwesomeTheme( bottomActionsBackgroundColor: Colors.cyan.withValues(alpha: 0.5), buttonTheme: AwesomeButtonTheme( backgroundColor: Colors.cyan.withValues(alpha: 0.5), iconSize: 20, foregroundColor: Colors.white, padding: const EdgeInsets.all(16), // Tap visual feedback (ripple, bounce...) buttonBuilder: (child, onTap) { return ClipOval( child: Material( color: Colors.transparent, shape: const CircleBorder(), child: InkWell( splashColor: Colors.cyan, highlightColor: Colors.cyan.withValues(alpha: 0.5), onTap: onTap, child: child, ), ), ); }, ), ), // Show the filter button on the top part of the screen topActionsBuilder: (state) => AwesomeTopActions( padding: EdgeInsets.zero, state: state, children: [ Expanded( child: AwesomeFilterWidget( state: state, filterListPosition: FilterListPosition.aboveButton, filterListPadding: const EdgeInsets.only(top: 8), ), ), ], ), // Show some Text with same background as the bottom part middleContentBuilder: (state) { return Column( children: [ const Spacer(), // Use a Builder to get a BuildContext below AwesomeThemeProvider widget Builder(builder: (context) { return Container( // Retrieve your AwesomeTheme's background color color: AwesomeThemeProvider.of(context) .theme .bottomActionsBackgroundColor, child: const Align( alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.only(bottom: 10, top: 10), child: Text( "Take your best shot!", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic, ), ), ), ), ); }), ], ); }, // Show Flash button on the left and Camera switch button on the right bottomActionsBuilder: (state) => AwesomeBottomActions( state: state, left: AwesomeFlashButton( state: state, ), right: AwesomeCameraSwitchButton( state: state, scale: 1.0, onSwitchTap: (state) { state.switchCameraSensor( aspectRatio: state.sensorConfig.aspectRatio, ); }, ), ), ) ``` -------------------------------- ### Initialize CameraAwesome UI Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Use CameraAwesomeBuilder.awesome to launch the full camera interface. The onMediaTap callback is used here to open captured media with the better_open_file package. ```dart CameraAwesomeBuilder.awesome( saveConfig: SaveConfig.photoAndVideo(), onMediaTap: (mediaCapture) { OpenFile.open(mediaCapture.filePath); }, ) ``` -------------------------------- ### Configure iOS permissions Source: https://docs.page/Apparence-io/camera_awesome/getting_started/installing Add required camera, microphone, and location usage descriptions to the Info.plist file. ```xml NSCameraUsageDescription Your own description NSMicrophoneUsageDescription To enable microphone access when recording video NSLocationWhenInUseUsageDescription To enable GPS location access for Exif data ``` -------------------------------- ### Toggling Image Analysis Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/reading_barcodes Use the start and stop methods on the AnalysisController to dynamically enable or disable image analysis. ```dart CheckboxListTile( value: widget.analysisController.enabled, onChanged: (_) async { // 1. if (widget.analysisController?.enabled == true) { // 2. await widget.analysisController.stop(); } else { // 3. await widget.analysisController.start(); } setState(() {}); }, title: Text("Enable barcode scan"), ) ``` -------------------------------- ### Apply a custom theme to CamerAwesome Source: https://docs.page/Apparence-io/camera_awesome/widgets/theming Configure the appearance of built-in widgets by passing an AwesomeTheme instance to the CameraAwesomeBuilder.awesome constructor. ```dart CameraAwesomeBuilder.awesome( theme: AwesomeTheme( // Background color of the bottom actions bottomActionsBackgroundColor: Colors.deepPurple.withValues(alpha: 0.5), // Buttons theme buttonTheme: AwesomeButtonTheme( // Background color of the button backgroundColor: Colors.deepPurple.withValues(alpha: 0.5), // Size of the icon iconSize: 32, // Padding around the icon padding: const EdgeInsets.all(18), // Color of the icon foregroundColor: Colors.lightBlue, // Tap visual feedback (ripple, bounce...) buttonBuilder: (child, onTap) { return ClipOval( child: Material( color: Colors.transparent, shape: const CircleBorder(), child: InkWell( splashColor: Colors.deepPurple, highlightColor: Colors.deepPurpleAccent.withValues(alpha: 0.5), onTap: onTap, child: child, ), ), ); }, ), ), ); ``` -------------------------------- ### Configure multiple cameras with CameraAwesomeBuilder Source: https://docs.page/Apparence-io/camera_awesome/getting_started/multicam Use SensorConfig.multiple to define a list of sensors for concurrent camera access. ```dart CameraAwesomeBuilder.awesome( // 1. sensorConfig: SensorConfig.multiple( // 2. sensors: [ Sensor.position(SensorPosition.back), Sensor.position(SensorPosition.front), ], // 3. flashMode: FlashMode.auto, aspectRatio: CameraAspectRatios.ratio_16_9, ), // Other params ) ``` -------------------------------- ### Configure initial camera settings Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Use SensorConfig to define aspect ratio, flash mode, sensor position, and zoom level during initialization. ```dart CameraAwesomeBuilder.awesome( sensorConfig: SensorConfig.single( aspectRatio: CameraAspectRatios.ratio_4_3, flashMode: FlashMode.auto, sensor: Sensor.position(SensorPosition.back), zoom: 0.0, ), ) ``` -------------------------------- ### Configure CamerAwesome for Barcode Analysis Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/reading_barcodes Set up the CameraAwesomeBuilder with an AnalysisConfig and image processing callback. ```dart // 1. CameraAwesomeBuilder.previewOnly( // 2. imageAnalysisConfig: AnalysisConfig( androidOptions: const AndroidAnalysisOptions.nv21( width: 1024, ), maxFramesPerSecond: 5, autoStart: false, ), // 3. onImageForAnalysis: (img) => _processImageBarcode(img), // 4. builder: (cameraModeState, preview) { return _BarcodeDisplayWidget( barcodesStream: _barcodesStream, scrollController: _scrollController, // 5. analysisController: cameraModeState.analysisController!, ); }, ) ``` -------------------------------- ### Configure CameraAwesomeBuilder with custom parameters Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Use this builder to define the camera UI, behavior, and configuration. Ensure all required builders and path providers are implemented to handle media capture and preview interactions. ```dart CameraAwesomeBuilder.awesome( // Bottom actions (take photo, switch camera...) bottomActionsBuilder: (state) { return AwesomeBottomActions( state: state, onMediaTap: _handleMediaTap, ); }, // Clicking on volume buttons will capture photo/video depending on the current mode enablePhysicalButton: true, // Filter to apply on the preview filter: AwesomeFilter.AddictiveRed, // Image analysis configuration imageAnalysisConfig: AnalysisConfig( androidOptions: const AndroidAnalysisOptions.nv21( width: 1024, ), autoStart: true, ), // Middle content (filters, photo/video switcher...) middleContentBuilder: (state) { // Use this to add widgets on the middle of the preview return Column( children: [ const Spacer(), AwesomeFilterWidget(state: state), Builder( builder: (context) => Container( color: AwesomeThemeProvider.of(context) .theme .bottomActionsBackgroundColor, height: 8, ), ), AwesomeCameraModeSelector(state: state), ], ); }, // Handle image analysis onImageForAnalysis: (analysisImage) { // Do some stuff with the image (see example) return processImage(analysisImage); }, onMediaTap: (mediaCapture) { // Hande tap on the preview of the last media captured print('Tap on ${mediaCapture.filePath}'); }, // Handle gestures on the preview, such as tap to focus or scale to zoom onPreviewTapBuilder: (state) => OnPreviewTap( onTap: (position, flutterPreviewSize, pixelPreviewSize) { // Handle tap to focus (default) or take a photo for instance // ... }, onTapPainter: (position) { // Tap feedback, here we just show a circle return Positioned( left: position.dx - 25, top: position.dy - 25, child: IgnorePointer( child: Container( decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), ), width: 50, height: 50, ), ), ); }, // Duration during which the feedback should be shown tapPainterDuration: const Duration(seconds: 2), ), // Handle scale gestures on the preview onPreviewScaleBuilder: (state) => OnPreviewScale( onScale: (scale) { // Do something with the scale value, set zoom for instance state.sensorConfig.setZoom(scale); }, ), // Alignment of the preview previewAlignment: Alignment.center, // Add your own decoration on top of the preview previewDecoratorBuilder: (state, preview) { // This will be shown above the preview (in a Stack) // It could be used in combination with MLKit to draw filters on faces for example return PreviewDecorationWiget(preview.rect); }, // Preview fit of the camera previewFit: CameraPreviewFit.fitWidth, // Padding around the preview previewPadding: const EdgeInsets.all(20), // Show a progress indicator while loading the camera progressIndicator: const Center( child: SizedBox( width: 100, height: 100, child: CircularProgressIndicator(), ), ), // Define if you want to take photos, videos or both and where to save them saveConfig: SaveConfig.photoAndVideo( initialCaptureMode: CaptureMode.photo, mirrorFrontCamera: true, photoPathBuilder: (sensors) async { // Return a valid file path (must be a jpg file) return SingleCaptureRequest('some/image/file/path.jpg', sensors.first); }, videoPathBuilder: (sensors) async { // Return a valid file path (must be a mp4 file) return SingleCaptureRequest('some/image/file/path.mp4', sensors.first); }, ), // Sensor initial configuration sensorConfig: SensorConfig.single( aspectRatio: CameraAspectRatios.ratio_4_3, flashMode: FlashMode.auto, sensor: Sensor.position(SensorPosition.back), zoom: 0.0, ), // CamerAwesome theme used to customize the built-in UI theme: AwesomeTheme( // Background color of the bottom actions bottomActionsBackgroundColor: Colors.deepPurple.withValues(alpha: 0.5), // Buttons theme buttonTheme: AwesomeButtonTheme( // Background color of the buttons backgroundColor: Colors.deepPurple.withValues(alpha: 0.5), // Buttons icon size iconSize: 32, // Padding around icons padding: const EdgeInsets.all(18), // Buttons icon color foregroundColor: Colors.lightBlue, // Tap visual feedback (ripple, bounce...) buttonBuilder: (child, onTap) { return ClipOval( child: Material( color: Colors.transparent, shape: const CircleBorder(), child: InkWell( ``` -------------------------------- ### Implement a custom camera UI with CameraAwesomeBuilder.custom Source: https://docs.page/Apparence-io/camera_awesome/getting_started/custom-ui Use the builder property to return a custom widget based on the current camera state. The camera preview is automatically rendered behind the returned widget. ```dart CameraAwesomeBuilder.custom( saveConfig: SaveConfig.photoAndVideo(), builder: (cameraState, preview) { // Return your UI (a Widget) return cameraState.when( onPreparingCamera: (state) => const Center(child: CircularProgressIndicator()), onPhotoMode: (state) => TakePhotoUI(state), onVideoMode: (state) => RecordVideoUI(state, recording: false), onVideoRecordingMode: (state) => RecordVideoUI(state, recording: true), ); }, ) ``` -------------------------------- ### Configure CamerAwesome for Face Analysis Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/detecting_faces Set up the CameraAwesomeBuilder to process image frames for analysis while providing a custom preview decorator. ```dart // 1. CameraAwesomeBuilder.previewOnly( // 2. previewFit: CameraPreviewFit.contain, sensorConfig: SensorConfig.single( sensor: Sensor.position(SensorPosition.front), aspectRatio: CameraAspectRatios.ratio_1_1, ), // 3. onImageForAnalysis: (img) => _analyzeImage(img), // 4. imageAnalysisConfig: AnalysisConfig( androidOptions: const AndroidAnalysisOptions.nv21( width: 250, ), maxFramesPerSecond: 5, // depending on your phone performances ), // 5. builder: (state, previewSize, previewRect) { return _MyPreviewDecoratorWidget( cameraState: state, faceDetectionStream: _faceDetectionController, previewSize: previewSize, previewRect: previewRect, ); }, ) ``` -------------------------------- ### Implement BarcodePreviewOverlay Build Method Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/reading_barcodes The build method uses IgnorePointer to pass touch events through to the camera and positions UI elements relative to the previewRect. ```dart // 1. IgnorePointer( ignoring: true, child: Padding( // 2. padding: EdgeInsets.only( top: widget.previewRect.top, left: widget.previewRect.left, right: _screenSize.width - widget.previewRect.right, bottom: _screenSize.height - widget.previewRect.bottom, ), child: Stack(children: [ // 3. Positioned.fill( child: CustomPaint( painter: BarcodeFocusAreaPainter( scanArea: _scanArea.size, barcodeRect: _barcodeRect, canvasScale: _canvasScale, canvasTranslate: _canvasTranslate, ), ), ), // 4. Positioned( // 5. top: widget.previewSize.height / 2 + _scanArea.size.height / 2 + 10, left: 0, right: 0, child: Column(children: [ Text( _barcodeRead ?? "", textAlign: TextAlign.center, style: const TextStyle( color: Colors.white, fontSize: 20, ), ), if (_barcodeInArea != null) Container( margin: const EdgeInsets.only(top: 8), color: _barcodeInArea! ? Colors.green : Colors.red, child: Text( _barcodeInArea! ? "Barcode in area" : "Barcode not in area", textAlign: TextAlign.center, style: const TextStyle( color: Colors.white, fontSize: 20, ), ), ), ]), ), ]), ), ) ``` -------------------------------- ### Implement AwesomeAspectRatioButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Configures a button to toggle between different camera aspect ratios. ```dart AwesomeAspectRatioButton( state: state, // Custom icon builder iconBuilder: (aspectRatio) { switch (aspectRatio) { case CameraAspectRatios.ratio_16_9: return const Icon(Icons.crop_16_9); case CameraAspectRatios.ratio_4_3: return const Icon(Icons.crop_7_5); case CameraAspectRatios.ratio_1_1: return const Icon(Icons.crop_square); default: return const SizedBox(); } }, // You can provide a custom theme to the button. If you don't, it will use the theme from CameraAwesomeBuilder theme: AwesomeTheme( buttonTheme: AwesomeButtonTheme( iconSize: 28, padding: const EdgeInsets.all(8), foregroundColor: Colors.black, backgroundColor: Colors.white, ), ), onAspectRatioTap: (sensorConfig, aspectRatio) { // Do something custom doSomething(); // Set the aspect ratio sensorConfig.setAspectRatio(aspectRatio); }, ) ``` -------------------------------- ### Configure iOS Podfile for Preview-Only Mode Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/image_analysis_configuration Add this to the Podfile to remove microphone API usage when only using preview mode on iOS. ```ruby post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) # ADD THE NEXT SECTION target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', 'AUDIO_SESSION_MICROPHONE=0' ] end end end ``` -------------------------------- ### Initialize BarcodeScanner Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/reading_barcodes Create a BarcodeScanner instance with specified formats. ```dart final _barcodeScanner = BarcodeScanner(formats: [BarcodeFormat.all]); ``` -------------------------------- ### Implement AwesomeCameraSwitchButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Configures a button to switch between front and back cameras with custom themes and behavior. ```dart AwesomeCameraSwitchButton( // Current CameraState state: state, // You can set a scale value for this button to make it look smaller or bigger than the other ones scale: 1.5, // You can provide a custom theme to the button. If you don't, it will use the theme from CameraAwesomeBuilder theme: AwesomeTheme( buttonTheme: AwesomeButtonTheme( iconSize: 28, padding: const EdgeInsets.all(8), foregroundColor: Colors.black, backgroundColor: Colors.white, ), ), // Change the switch camera behaviour logic onSwitchTap: (state) { // Aspect ratio is reset by default when switching cameras (it goes back to 4:3). // You can change this behaviour by overriding the aspect ratio in the switchCameraSensor method. state.switchCameraSensor( aspectRatio: state.sensorConfig.aspectRatio, ); }, // Set the icon you want to display for the switch camera button iconBuilder: () { return MyCustomIcon(); }, ) ``` -------------------------------- ### Implement AwesomeCaptureButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Provides a simple capture button for photo or video modes. ```dart AwesomeCaptureButton(state: state) ``` -------------------------------- ### CameraState API Source: https://docs.page/Apparence-io/camera_awesome/getting_started/custom-ui General methods and properties available to all CameraState instances. ```APIDOC ## CameraState Methods - `state.switchCameraSensor()`: Switch between FRONT and BACK camera. - `state.sensorConfig`: Get current Sensor configuration. - `state.sensorConfig$`: Stream of current Sensor configuration. - `state.saveConfig`: Get original SaveConfig. ``` -------------------------------- ### Implement Preview Decorator Widget for Face Detection Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/detecting_faces Uses a StreamBuilder to listen to camera sensor configuration and face detection results, applying necessary canvas transformations before painting. ```dart class _MyPreviewDecoratorWidget extends StatelessWidget { final CameraState cameraState; final Stream faceDetectionStream; final Preview preview; const _MyPreviewDecoratorWidget({ required this.cameraState, required this.faceDetectionStream, required this.preview, }); @override Widget build(BuildContext context) { return IgnorePointer( child: StreamBuilder( // 1. stream: cameraState.sensorConfig$, builder: (_, snapshot) { if (!snapshot.hasData) { return const SizedBox(); } else { return StreamBuilder( // 2. stream: faceDetectionStream, builder: (_, faceModelSnapshot) { if (!faceModelSnapshot.hasData) return const SizedBox(); // this is the transformation needed to convert the image to the preview // Android mirrors the preview but the analysis image is not final canvasTransformation = faceModelSnapshot.data!.img ?.getCanvasTransformation(preview); // 3. return CustomPaint( painter: FaceDetectorPainter( model: faceModelSnapshot.requireData, canvasTransformation: canvasTransformation, preview: preview, ), ); }, ); } }, ), ); } } ``` -------------------------------- ### Configure Android SDK version Source: https://docs.page/Apparence-io/camera_awesome/getting_started/installing Set the minimum SDK version to 21 or higher in the app-level build.gradle file. ```text minSdkVersion 21 ``` -------------------------------- ### Check multi-camera support Source: https://docs.page/Apparence-io/camera_awesome/getting_started/multicam Verify if the current device supports concurrent camera features before initialization. ```dart final isSupported = await CamerawesomePlugin.isMultiCamSupported() ``` -------------------------------- ### SensorConfig Constructor Definition Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Displays the default configuration parameters for the camera sensor. ```dart SensorConfig({ required this.sensor, FlashMode flash = FlashMode.none, SensorType type = SensorType.wideAngle, this.captureDeviceId, CameraAspectRatios aspectRatio = CameraAspectRatios.ratio_4_3, double currentZoom = 0.0, }) ``` -------------------------------- ### Add dependency to pubspec.yaml Source: https://docs.page/Apparence-io/camera_awesome/getting_started/installing Include the camerawesome package in your project's dependencies. ```yaml dependencies: camerawesome: ^2.0.0 ... ``` -------------------------------- ### Implement AwesomeLocationButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Configures a button to toggle GPS metadata saving for captured photos. ```dart AwesomeLocationButton( // Current CameraState state: state, // Change the icon based on saveGpsLocation iconBuilder: (saveGpsLocation) { if (saveGpsLocation) { return const Icon(Icons.location_pin); } else { return const Icon(Icons.location_off_outlined); } }, // You can provide a custom theme to the button. If you don't, it will use the theme from CameraAwesomeBuilder theme: AwesomeTheme( buttonTheme: AwesomeButtonTheme( iconSize: 28, padding: const EdgeInsets.all(8), foregroundColor: Colors.black, backgroundColor: Colors.white, ), ), // Change the location button behaviour logic onLocationTap: (state, saveGpsLocation) { // Your custom logic doSomethingCustom(); // Default logic state.shouldSaveGpsLocation(saveGpsLocation); }, ) ``` -------------------------------- ### AwesomeAspectRatioButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons A button widget to cycle through supported camera aspect ratios (4:3, 16:9, 1:1). ```APIDOC ## AwesomeAspectRatioButton ### Description A button that allows users to change the aspect ratio of the camera. Supported ratios are 4:3, 16:9, and 1:1. ### Parameters - **state** (CameraState) - Required - The current camera state. - **iconBuilder** (Function) - Optional - Builder to provide custom icons based on the current aspect ratio. - **theme** (AwesomeTheme) - Optional - Custom theme configuration. - **onAspectRatioTap** (Function) - Optional - Callback to execute custom logic when the button is tapped. ``` -------------------------------- ### CameraAwesomeBuilder.custom Source: https://docs.page/Apparence-io/camera_awesome/getting_started/custom-ui The custom constructor allows you to define a custom UI builder while the camera preview remains visible behind your widgets. ```APIDOC ## CameraAwesomeBuilder.custom ### Description Creates a custom camera interface by providing a builder function that receives the current camera state and the preview widget. ### Parameters - **saveConfig** (SaveConfig) - Required - Defines photo/video capture settings and storage locations. - **builder** (Function) - Required - A function that returns a Widget based on the current camera state (onPreparingCamera, onPhotoMode, onVideoMode, onVideoRecordingMode). ### Example ```dart CameraAwesomeBuilder.custom( saveConfig: SaveConfig.photoAndVideo(), builder: (cameraState, preview) { return cameraState.when( onPreparingCamera: (state) => const Center(child: CircularProgressIndicator()), onPhotoMode: (state) => TakePhotoUI(state), onVideoMode: (state) => RecordVideoUI(state, recording: false), onVideoRecordingMode: (state) => RecordVideoUI(state, recording: true), ); }, ) ``` ``` -------------------------------- ### Configure image analysis with AnalysisConfig Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/image_analysis_configuration Use AnalysisConfig to define platform-specific settings, frame rates, and auto-start behavior for image analysis streams. ```dart CameraAwesomeBuilder.awesome( // Other parameters... onImageForAnalysis: (AnalysisImage img) { // Handle image analysis }, imageAnalysisConfig: AnalysisConfig( // 1. androidOptions: const AndroidAnalysisOptions.nv21( width: 250, ), // 2. autoStart: true, // 3. cupertinoOptions: const CupertinoAnalysisOptions.bgra8888(), // 4. maxFramesPerSecond: 20, ), ) ``` -------------------------------- ### Update CameraAwesomeBuilder configuration Source: https://docs.page/Apparence-io/camera_awesome/migration_guides/from_1_to_2 Migrate from legacy flat configuration parameters to the new SensorConfig and SaveConfig structures. ```diff CameraAwesomeBuilder.awesome( - sensor: Sensors.back, - flashMode: FlashMode.auto, - aspectRatio: CameraAspectRatios.ratio_4_3, - mirrorFrontCamera: true, - zoom: 0.0, + sensorConfig: SensorConfig.single( + sensor: Sensor.position(SensorPosition.back), + flashMode: FlashMode.auto, + aspectRatio: CameraAspectRatios.ratio_4_3, + zoom: 0.0, + ), - exifPreferences: ExifPreferences(saveGPSLocation: true), - enableAudio: true, saveConfig: SaveConfig.photoAndVideo( initialCaptureMode: CaptureMode.photo, + photoPathBuilder: (sensors) async { + final Directory extDir = await getTemporaryDirectory(); + final testDir = await Directory( + '${extDir.path}/camerawesome', + ).create(recursive: true); + if (sensors.length == 1) { + final String filePath = + '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg'; + return SingleCaptureRequest(filePath, sensors.first); + } else { + // Separate pictures taken with front and back camera + return MultipleCaptureRequest( + { + for (final sensor in sensors) + sensor: + '${testDir.path}/${sensor.position == SensorPosition.front ? 'front_' : "back_"}${DateTime.now().millisecondsSinceEpoch}.jpg', + }, + ); + } + }, + videoPathBuilder: (sensors) async { + // same logic as photoPathBuilder + }, + videoOptions: VideoOptions( + enableAudio: true, + ios: CupertinoVideoOptions( + fps: 10, + ), + android: AndroidVideoOptions( + bitrate: 6000000, + quality: VideoRecordingQuality.fhd, + fallbackStrategy: QualityFallbackStrategy.lower, + ), + ), + exifPreferences: ExifPreferences(saveGPSLocation: true), + mirrorFrontCamera: true, ), ... ) ``` -------------------------------- ### Configure SaveConfig for Media Capture Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Customize capture behavior including initial modes, file paths, video quality settings, and EXIF preferences. ```dart SaveConfig.photoAndVideo( // 1. initialCaptureMode: CaptureMode.photo, // 2. photoPathBuilder: (sensors) async { ... }, // 3. videoPathBuilder: (sensors) async { ... }, // 4. videoOptions: VideoOptions( enableAudio: true, ios: CupertinoVideoOptions( fps: 10, // TODODOC Add other possble params ), android: AndroidVideoOptions( bitrate: 6000000, quality: VideoRecordingQuality.fhd, fallbackStrategy: QualityFallbackStrategy.lower, ), ), // 5. exifPreferences: ExifPreferences(saveGPSLocation: true), // 6. mirrorFrontCamera: true, ) ``` -------------------------------- ### Adjust Camera Preview Positioning Source: https://docs.page/Apparence-io/camera_awesome/getting_started/awesome-ui Configure the camera preview area using previewPadding and previewAlignment parameters. ```dart CameraAwesomeBuilder.awesome( previewPadding: const EdgeInsets.all(20), previewAlignment: Alignment.center, // Other parameters ... ) ``` -------------------------------- ### Configure Picture-in-Picture Preview Source: https://docs.page/Apparence-io/camera_awesome/getting_started/multicam Use the pictureInPictureConfigBuilder to return a PictureInPictureConfig object for each sensor, allowing for custom positioning, interaction, and UI rendering. ```dart CameraAwesomeBuilder.awesome( pictureInPictureConfigBuilder: (index, sensor) { const width = 200.0; return PictureInPictureConfig( // 1. isDraggable: false, // 2. startingPosition: Offset( screenSize.width - width - 20.0 * index, screenSize.height - 356, ), // 3. sensor: sensor, // 4. onTap: (){ print('on preview tap'); }, // 5. pictureInPictureBuilder: (preview, aspectRatio) { return SizedBox( width: width, height: width, child: ClipPath( clipper: _MyCustomPipClipper( width: width, height: width * aspectRatio, shape: shape, ), child: SizedBox( width: width, // 6. child: preview, ), ), ); }, ); }, ) ``` -------------------------------- ### Implement AwesomePauseResumeButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Use this widget to control video recording state. It supports custom theming via AwesomeTheme. ```dart AwesomePauseResumeButton( state: videoRecordingCameraState, // You can provide a custom theme to the button. If you don't, it will use the theme from CameraAwesomeBuilder theme: AwesomeTheme( buttonTheme: AwesomeButtonTheme( iconSize: 28, padding: const EdgeInsets.all(8), foregroundColor: Colors.black, backgroundColor: Colors.white, ), ), ) ``` -------------------------------- ### Initialize FaceDetector Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/detecting_faces Configure the MLKit FaceDetector with options for contours, landmarks, and classification. ```dart final options = FaceDetectorOptions( enableContours: true, enableClassification: true, enableLandmarks: true, ); late final faceDetector = FaceDetector(options: options); ``` -------------------------------- ### Handle camera states with pattern matching Source: https://docs.page/Apparence-io/camera_awesome/getting_started/custom-ui Uses the state pattern to execute specific actions based on the current camera mode. ```dart state.when( onAnalysisOnlyMode: (analysisCameraState) => analysisCameraState.startAnalysis(), onPhotoMode: (photoCameraState) => photoCameraState.takePhoto(), onVideoMode: (videoCameraState) => videoCameraState.startRecording(), onVideoRecordingMode: (videoRecordingCameraState) => videoRecordingCameraState.stopRecording(), onPreparingCamera: (preparingCameraState) => Loader(), onPreviewMode: (previewCameraState) => previewModeState.focus(), ); ``` -------------------------------- ### Implement AwesomeSensorTypeSelector Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Provides a UI to switch between available camera sensors on iOS. Requires a valid camera state. ```dart AwesomeSensorTypeSelector(state: state) ``` -------------------------------- ### Displaying Media Preview with AwesomeMediaPreview Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons Uses a StreamBuilder to listen to capture states and display the last captured media. Video preview is not supported by this widget. ```dart StreamBuilder( stream: state.captureState$, builder: (context, snapshot) { if (!snapshot.hasData) { return Container(width: 72, height: 72); } return SizedBox( width: 72, child: AwesomeMediaPreview( mediaCapture: snapshot.requireData, onMediaTap: onMediaTap, ), ); }, ) ``` -------------------------------- ### Handle AnalysisImage formats with when() Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/image_format_conversions Use the when() helper function to pattern match on the specific AnalysisImage implementation and execute format-specific logic. ```dart final Widget? result = img.when(jpeg: (JpegImage image) { return handleJpeg(image); }, yuv420: (Yuv420Image image) { return handleYuv420( image); }, nv21: (Nv21Image image) { return handleNv21(image); }, bgra8888: (Bgra8888Image image) { return handleBgra8888(image); }) ``` -------------------------------- ### Import package in Flutter Source: https://docs.page/Apparence-io/camera_awesome/getting_started/installing Import the main CamerAwesome library into your Dart files. ```dart import 'package:camerawesome/camerawesome_plugin.dart'; ``` -------------------------------- ### Convert Image Point to Preview Coordinates Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/reading_barcodes Utility method to map a point from the raw analysis image to the preview display, handling device-specific orientation and mirroring. ```dart /// this method is used to convert a point from an image to the preview /// according to the current preview size and the image size /// also in case of Android, it will flip the point if required Offset convertFromImage( Offset point, AnalysisImage img, ); ``` -------------------------------- ### Create a Custom Flash Button Widget Source: https://docs.page/Apparence-io/camera_awesome/getting_started/custom-ui Uses StreamBuilder to listen to sensorConfig$ and flashMode$ for reactive UI updates. Ensure the widget is provided with a valid CameraState instance. ```dart class AwesomeFlashButton extends StatelessWidget { final CameraState state; const AwesomeFlashButton({ super.key, required this.state, }); @override Widget build(BuildContext context) { return StreamBuilder( // Listen to the current SensorConfig. It might change when switching between front and back cameras. stream: state.sensorConfig$, builder: (_, sensorConfigSnapshot) { if (!sensorConfigSnapshot.hasData) { return const SizedBox.shrink(); } final sensorConfig = sensorConfigSnapshot.requireData; return StreamBuilder( // Listen to the currently selected flash mode stream: sensorConfig.flashMode$, builder: (context, snapshot) { if (!snapshot.hasData) { return Container(); } return _FlashButton.from( // Build your button differently based on the current Flash mode, with different icons for instance flashMode: snapshot.requireData, onTap: () => sensorConfig.switchCameraFlash(), ); }, ); }, ); } } ``` -------------------------------- ### AwesomeCaptureButton Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_buttons A button widget to trigger photo capture or video recording based on the current camera mode. ```APIDOC ## AwesomeCaptureButton ### Description A button that takes a photo when in Photo mode or starts/stops recording when in Video mode. ### Parameters - **state** (CameraState) - Required - The current camera state. ``` -------------------------------- ### Implement CameraPreviewDisplayer Widget Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/image_format_conversions A StatefulWidget that consumes an AnalysisImage stream, converts various image formats to JPEG, and applies filters before rendering. ```dart class CameraPreviewDisplayer extends StatefulWidget { final Stream analysisImageStream; const CameraPreviewDisplayer({ super.key, required this.analysisImageStream, }); @override State createState() => _CameraPreviewDisplayerState(); } class _CameraPreviewDisplayerState extends State { // 1. Uint8List? _cachedJpeg; @override Widget build(BuildContext context) { return Center( // 2. child: StreamBuilder( stream: widget.analysisImageStream, builder: (_, snapshot) { if (!snapshot.hasData) { return const SizedBox.shrink(); } final img = snapshot.requireData; // 3. return img.when(jpeg: (image) { // 4. _cachedJpeg = _applyFilterOnBytes(image.bytes); return ImageAnalysisPreview( currentJpeg: _cachedJpeg!, width: image.width.toDouble(), height: image.height.toDouble(), ); }, yuv420: (Yuv420Image image) { // 5. return FutureBuilder( future: image.toJpeg(), builder: (_, snapshot) { if (snapshot.data == null && _cachedJpeg == null) { return const Center( child: CircularProgressIndicator(), ); } else if (snapshot.data != null) { // 6. _cachedJpeg = _applyFilterOnBytes( snapshot.data!.bytes, ); } return ImageAnalysisPreview( currentJpeg: _cachedJpeg!, width: image.width.toDouble(), height: image.height.toDouble(), ); }); }, nv21: (Nv21Image image) { // 7. return FutureBuilder( future: image.toJpeg(), builder: (_, snapshot) { if (snapshot.data == null && _cachedJpeg == null) { return const Center( child: CircularProgressIndicator(), ); } else if (snapshot.data != null) { _cachedJpeg = _applyFilterOnBytes( snapshot.data!.bytes, ); } return ImageAnalysisPreview( currentJpeg: _cachedJpeg!, width: image.width.toDouble(), height: image.height.toDouble(), ); }); }, bgra8888: (Bgra8888Image image) { // 8. _cachedJpeg = _applyFilterOnImage( imglib.Image.fromBytes( width: image.width, height: image.height, bytes: image.planes[0].bytes.buffer, order: imglib.ChannelOrder.bgra, ), ); return ImageAnalysisPreview( currentJpeg: _cachedJpeg!, width: image.width.toDouble(), height: image.height.toDouble(), ); // We handle all formats so we're sure there won't be a null value })!; }, ), ); } Uint8List _applyFilterOnBytes(Uint8List bytes) { return _applyFilterOnImage(imglib.decodeJpg(bytes)!); } Uint8List _applyFilterOnImage(imglib.Image image) { // 9. return imglib.encodeJpg( imglib.billboard(image), quality: 70, ); } } ``` -------------------------------- ### Implement AnalysisImage to InputImage Extension Source: https://docs.page/Apparence-io/camera_awesome/image_analysis/reading_barcodes Provides an extension on AnalysisImage to handle conversion to MLKit's InputImage format for both NV21 and BGRA8888 image types. ```dart import 'package:camerawesome/camerawesome_plugin.dart'; import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; extension MLKitUtils on AnalysisImage { InputImage toInputImage() { // 1. final planeData = when(nv21: (img) => img.planes, bgra8888: (img) => img.planes)?.map( (plane) { return InputImagePlaneMetadata( bytesPerRow: plane.bytesPerRow, height: height, width: width, ); }, ).toList(); // 2. return when(nv21: (image) { // 3. return InputImage.fromBytes( bytes: image.bytes, metadata: InputImageMetadata( rotation: inputImageRotation, format: InputImageFormat.nv21, size: image.size, bytesPerRow: image.planes.first.bytesPerRow, ), ); }, bgra8888: (image) { // 4. final inputImageData = InputImageData( size: size, imageRotation: inputImageRotation, inputImageFormat: inputImageFormat, planeData: planeData, ); // 5. return InputImage.fromBytes( bytes: image.bytes, inputImageData: inputImageData, ); })!; } InputImageRotation get inputImageRotation => InputImageRotation.values.byName(rotation.name); InputImageFormat get inputImageFormat { switch (format) { case InputAnalysisImageFormat.bgra8888: return InputImageFormat.bgra8888; case InputAnalysisImageFormat.nv21: return InputImageFormat.nv21; default: return InputImageFormat.yuv420; } } } ``` -------------------------------- ### Configuring AwesomeBottomActions Source: https://docs.page/Apparence-io/camera_awesome/widgets/layout Customizing the bottom actions area, including the capture button and side widgets. ```dart AwesomeBottomActions( // CameraState is required state: state, // You can set your own capture button captureButton: MyCaptureButton( state: state, ), // Padding around the bottom actions padding: const EdgeInsets.only( bottom: 16, left: 8, right: 8, ), // Widget to the left of the captureButton left: AwesomeFlashButton( state: state, ), // Widget to the right of the captureButton right: AwesomeCameraSwitchButton( state: state, scale: 1.0, onSwitchTap: (state) { state.switchCameraSensor( aspectRatio: state.sensorConfig.aspectRatio, ); }, ), // Callback used by default values. Don't specify it if you override left and right widgets. onMediaTap: null, ); ``` -------------------------------- ### Add Android audio recording permission Source: https://docs.page/Apparence-io/camera_awesome/getting_started/installing Include the RECORD_AUDIO permission in the AndroidManifest.xml file for video recording. ```xml ``` -------------------------------- ### Access the current theme Source: https://docs.page/Apparence-io/camera_awesome/widgets/theming Retrieve the active AwesomeTheme instance from the widget tree using the AwesomeThemeProvider. ```dart final myTheme = AwesomeThemeProvider.of(context).theme ``` -------------------------------- ### Apply a filter in CameraAwesomeBuilder Source: https://docs.page/Apparence-io/camera_awesome/widgets/awesome_filters Use the filter parameter within the CameraAwesomeBuilder.awesome constructor to apply a specific filter. ```dart CameraAwesomeBuilder.awesome( // [...] filter: AwesomeFilter.AddictiveRed, ), ```