darwin_camera 0.0.2

  • Readme
  • Changelog
  • Example
  • Installing
  • 75

Darwin Camera #

Darwin camera makes it super easy to add camera to your Flutter app. It uses the official camera plugin implementation underneath.

  • Captures RAW image at maximum resolution supported by the device camera.
  • Provides a toggle between front and back camera.
    • You can configure what it defaults to on opening.
  • Provides configuration to set quality of the captured image.
  • Provides a minimal UI for the reviewing the capture before saving image.
  • Supports both Android and iOS.
Camera StreamPreview Captured Image
Press the white circular button to capture image.Press the green button to save the image.
Press the button at the bottom right to toggle camera.Press the close button to discard the captured image.

Getting Started #

In your flutter project add darwin_camera as a dependency in pubspec.yaml:

dependencies:
  ...
  darwin_camera:
    git: https://github.com/atlanhq/darwin-camera
    

iOS #

Add two rows to the ios/Runner/Info.plist:

  • one with the key Privacy - Camera Usage Description and a usage description.
  • and one with the key Privacy - Microphone Usage Description and a usage description.

Or in text format add the key:

<key>NSCameraUsageDescription</key>
<string>Can I use the camera please?</string>
<key>NSMicrophoneUsageDescription</key>
<string>Can I use the mic please?</string>

Android #

Change the minimum Android sdk version to 21 (or higher) in your android/app/build.gradle file.

minSdkVersion 21

Usage example #

import 'package:darwin_camera/darwin_camera.dart';

 DarwinCameraResult result = await Navigator.push(
   context,
   MaterialPageRoute(
     builder: (context) => DarwinCamera(
       cameraDescription: cameraDescription,
       filePath: filePath,
       resolution: ResolutionPreset.high,
       defaultToFrontFacing: false,
       quality: 90,
     ),
   ),
 );

if (result != null && result.isFileAvailable) {
   /// File object returned by Camera.
   print(result.file);
   /// Path where the file is faced. 
   print(result.file.path);
 }

DarwinCamera configuration #

This widget captures an image and save it at the path provided by you.

DarwinCamera({
  
  ///
  /// Flag to enable/disable image compression.
  bool enableCompression = false, 
  
  ///
  /// Disables swipe based native back functionality provided by iOS.
  bool disableNativeBackFunctionality = false,
  
  /// @Required
  /// List of cameras availale in the device.
  /// 
  /// How to get the list available cameras?
  /// `List<CameraDescription> cameraDescription = await availableCameras();`
  List<CameraDescription> cameraDescription, 
  
  /// @Required
  
  /// Path where the image file will be saved.
  String filePath, 
  
  /// 
  /// Resolution of the image captured
  /// Possible values:
  /// 1. ResolutionPreset.high
  /// 2. ResolutionPreset.medium
  /// 3. ResolutionPreset.low
  ResolutionPreset resolution = ResolutionPreset.high, 

  ///
  /// Open front camera instead of back camera on launch.
  bool defaultToFrontFacing = false;

  ///
  /// Decides the quality of final image captured.
  /// Possible values `0 - 100`
  int quality = 90;

})

Complete example with permission handling. #

See the example directory in the github repository

Tests #

cd example
flutter drive --target=test_driver/app.dart

How to contribute? #

See CONTRIBUTING.md

0.0.2 #

  • Updated author information, plugin description, changelog and example/README.md.

0.0.1 #

  • This is the first release of Darwin Camera. All the features in this release are described in the README.md.

example/lib/main.dart

import 'dart:io';

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:darwin_camera/darwin_camera.dart';

import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {


  @override
  void initState() {
    super.initState();
  }


  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Darwin Camera Plugin'),
        ),
        body: DarwinCameraTutorial(),
      ),
    );
  }
}

class DarwinCameraTutorial extends StatefulWidget {
  const DarwinCameraTutorial({Key key}) : super(key: key);

  @override
  _DarwinCameraTutorialState createState() => _DarwinCameraTutorialState();
}

class _DarwinCameraTutorialState extends State<DarwinCameraTutorial> {
  File imageFile;
  bool isImageCaptured;

  @override
  void initState() {
    super.initState();

    isImageCaptured = false;
  }

  openCamera(BuildContext context) async {
    PermissionHandler permissionHandler = PermissionHandler();

    await checkForPermissionBasedOnPermissionGroup(
      permissionHandler,
      PermissionGroup.camera,
    );

    ///
    /// Microphone permission is required for android devices.
    /// if permission isn't given before opening camera. 
    /// The app will crash.
    /// 
    /// For iOS devices, it's not neccessary. You can skip microphone permission.
    /// Required for android devices. 
    await checkForPermissionBasedOnPermissionGroup(
      permissionHandler,
      PermissionGroup.microphone,
    );

    ///
    String filePath = await FileUtils.getDefaultFilePath();
    String uuid = DateTime.now().millisecondsSinceEpoch.toString();

    ///
    filePath = '$filePath/$uuid.png';

    List<CameraDescription> cameraDescription = await availableCameras();

    ////
    DarwinCameraResult result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => DarwinCamera(
          cameraDescription: cameraDescription,
          filePath: filePath,
          resolution: ResolutionPreset.high,
          defaultToFrontFacing: false,
          quality: 90,
        ),
      ),
    );

    ///
    ///
    if (result != null && result.isFileAvailable) {
      setState(() {
        isImageCaptured = true;
        imageFile = result.file;
      });
      print(result.file);
      print(result.file.path);
    }

    ///
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          SizedBox(
            height: 40.0,
          ),
          Padding(
            padding: EdgeInsets.all(16),
            child: ButtonWithImage(
              key: ValueKey("OpenDarwinCameraButton"),
              title: "Open Darwin Camera",
              iconData: Icons.camera_alt,
              onTap: () {
                print("[+] OPEN CAMERA");
                openCamera(context);
              },
            ),
          ),
          if (isImageCaptured)
            Container(
              margin: padding_a_xs,
              padding: padding_a_xxs,
              decoration: BoxDecoration(
                color: DarwinPrimaryLight,
                borderRadius: BorderRadius.circular(grid_spacer * 2),
              ),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(grid_spacer),
                child: Image.file(
                  imageFile,
                  key: ValueKey("CapturedImagePreview"),
                  fit: BoxFit.fitHeight,
                  alignment: Alignment.center,
                  height: 300,
                ),
              ),
            )
        ],
      ),
    );
  }
}

Future<bool> checkForPermissionBasedOnPermissionGroup(
  PermissionHandler permissionHandler,
  PermissionGroup permissionType,
) async {
  ///
  PermissionStatus permission;
  permission = await permissionHandler.checkPermissionStatus(permissionType);
  if (permission == PermissionStatus.granted) {
    // takeImageFromCameraAndSave();
    return true;
  }
  var status = await permissionHandler.requestPermissions([permissionType]);
  permission = status[permissionType];

  if (permission == PermissionStatus.granted) {
    // takeImageFromCameraAndSave();
    return true;
  } else {
    ///
    /// ASK USER TO GO TO SETTINGS TO GIVE PERMISSION;

    return false;
  }
}

class FileUtils {
  static Future<String> getDefaultFilePath() async {
    try {
      Directory appDocDir = await getApplicationDocumentsDirectory();
      String mediaDirectory = appDocDir.path + "/media";
      Directory(mediaDirectory).create(recursive: true);
      return mediaDirectory;
    } catch (error, stacktrace) {
      print('could not create folder for media assets');
      print(error);
      print(stacktrace);
      return null;
    }
  }
}

class ButtonWithImage extends StatelessWidget {
  final Key key;
  final VoidCallback onTap;
  final EdgeInsets padding;
  final Icon icon;
  final IconData iconData;
  final String title;

  ButtonWithImage({
    this.key,
    @required this.onTap,
    this.padding,
    this.icon,
    this.iconData,
    this.title,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: DarwinPrimaryLight,
        borderRadius: BorderRadius.circular(grid_spacer * 2),
      ),
      child: InkWell(
        onTap: onTap,
        child: Center(
          child: Container(
            margin: margin_a_s,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                Icon(
                  iconData,
                  color: DarwinPrimary,
                  size: grid_spacer * 5,
                ),
                SizedBox(
                  width: grid_spacer * 1.5,
                ),
                Text(
                  title.toUpperCase(),
                  style: Theme.of(context).textTheme.display1.copyWith(
                        color: DarwinPrimary,
                        height: 1.2,
                        fontSize: 20,
                      ),
                  textAlign: TextAlign.left,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  darwin_camera: ^0.0.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:darwin_camera/darwin_camera.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
57
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
86
Overall:
Weighted score of the above. [more]
75
Learn more about scoring.

We analyzed this package on Apr 4, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Health suggestions

Fix lib/core/ui.dart. (-1 points)

Analysis of lib/core/ui.dart reported 2 hints:

line 64 col 10: The value of the local variable 'size' isn't used.

line 435 col 7: This class (or a class which this class inherits from) is marked as '@immutable', but one or more of its instance fields are not final: LoaderOverlay.isVisible

Format lib/core/core.dart.

Run flutter format to format lib/core/core.dart.

Format lib/theme/colors.dart.

Run flutter format to format lib/theme/colors.dart.

Fix additional 3 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/theme/darwin_font_icons.dart (Run flutter format to format lib/theme/darwin_font_icons.dart.)
  • lib/theme/dimensions.dart (Run flutter format to format lib/theme/dimensions.dart.)
  • lib/theme/texts.dart (Run flutter format to format lib/theme/texts.dart.)

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

The package description is too short. (-4 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
camera ^0.5.2+1 0.5.7+4
flutter 0.0.0
flutter_image_compress ^0.6.3 0.6.5+1
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_driver
flutter_test