[AVLE Refactoring] Taking a Photo (Flutter Web)

in avle •  2 years ago 

I refactored taking a photo code of AVLE.

Taking a photo was working well in desktop but it was not in mobile devices.

I've struggled all day to find out the cause and finally resolved the issue.

image.png

What I did was to change camera package from image_picker_web to image_picker_for_web.

And I noticed that taking a photo function is different on different browsers. For example, Safari and Samsung browsers show the camera option when choosing 'Gallery' but Chrome and Brave do not.

I confirmed that taking a photo on mobile devices is working great!

Here is the code for Flutter to capture an image from a camera

camera control class


class CameraControl {
  late List<CameraDescription> cameras;
  CameraController? controller;
  int cameraIndex = 0;

  CameraControl() {
    // initialize();
  }

  Future<void> initialize() async {
    cameras = await availableCameras();
    print('CameraControl. initialize. cameras: $cameras');
    print('CameraControl. initialize. camera count: ${cameras.length}');

    if (cameras.length > 0) {
      await onNewCameraSelected(cameras[0]);
      print('CameraControl. onNewCameraSelected');
    }
  }

  Future<void> onNewCameraSelected(CameraDescription cameraDescription) async {
    if (controller != null) {
      print('onNewCameraSelected. dispose controller first');
      await controller!.dispose();
    }

    final CameraController cameraController = CameraController(
      cameraDescription,
      ResolutionPreset.max,
      enableAudio: false,
      imageFormatGroup: ImageFormatGroup.jpeg,
    );

    controller = cameraController;

    try {
      await cameraController.initialize();
      print('onNewCameraSelected. camera is initialized');
    } on CameraException catch (e) {
      print('camera execption: $e');
    }
  }

  Future<void> switchCamera() async {
    // if (cameraIndex == 0 && cameras.length > 0) {
    //   cameraIndex = 1;
    // }
    // if (cameraIndex > 0) {
    //   cameraIndex = 0;
    // }

    print('switch camera. before. cameraIndex: $cameraIndex');

    cameraIndex++;
    if (cameraIndex >= cameras.length) {
      cameraIndex = 0;
    }

    print('switch camera. after cameraIndex: $cameraIndex');

    print('camera description: ${cameras[cameraIndex]}');
    await onNewCameraSelected(cameras[cameraIndex]);
  }

  Future<XFile?> takeSceenshot() async {
    final CameraController? cameraController = controller;
    if (cameraController == null || !cameraController.value.isInitialized) {
      print('Camera is empty');
      return null;
    }
    try {
      XFile file = await cameraController.takePicture();
      return file;
    } on CameraException catch (e) {
      print('failed to take sceenshot. $e');
      // TODO: show snackbar
      // dispose controller
      controller!.dispose();
      return null;
    }
  }

  Future<void> disposeController() async {
    if (controller != null) {
      await controller!.dispose();
    }
  }
}

capture main

_capturePhoto({required BuildContext context}) async {
    printWarning('capture video');

    // close the bottom sheet
    Get.back();

    CameraControl cameraController = CameraControl();
    await cameraController.initialize();

    showCameraDialog(
      cameraController: cameraController,
      onTakeStarted: () {
        if (onImageSelected != null) {
          onImageSelected!();
        }
      },
      onPhotoTaken: (frame) {
        // dispose the camera
        cameraController.disposeController();
        _uploadCameraImage(frame: frame);
      },
    );
}

Capture stream dialog

showCameraDialog({
  required CameraControl cameraController,
  required VoidCallback onTakeStarted,
  required Function onPhotoTaken,
}) {
  Get.defaultDialog(
    title: 'CameraDialog_title'.tr,
    content: _buildBody(
      cameraController: cameraController,
      onTakeStarted: onTakeStarted,
      onPhotoTaken: onPhotoTaken,
    ),
  );
}

Widget _buildBody({
  required CameraControl cameraController,
  required VoidCallback onTakeStarted,
  required Function onPhotoTaken,
}) {
  if (cameraController.controller == null || cameraController.cameras.isEmpty) {
    print('camera dialog. No camera found');
    return const CircularProgressIndicator();
  }
  print('camera dialog build body');
  return StatefulBuilder(
    builder: (context, setState) {
      print(
          'camera dialog builder. camera controller: ${cameraController.controller}');

      return SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height / 1.5,
        child: Column(
          children: [
            Expanded(
              child: Card(
                child: CameraPreview(
                  cameraController.controller!,
                  child: LayoutBuilder(builder:
                      (BuildContext context, BoxConstraints constraints) {
                    return GestureDetector(
                      behavior: HitTestBehavior.opaque,
                    );
                  }),
                ),
              ),
            ),
            const Divider(),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  TextButton(
                    onPressed: () async {
                      print('CameraDialgo_take');
                      onTakeStarted();
                      final file = await cameraController.takeSceenshot();
                      if (file != null) {
                        // get bytes
                        final bytes = await file.readAsBytes();
                        onPhotoTaken(bytes);
                        Get.back();
                      }
                    },
                    child: Text('CameraDialog_take'.tr),
                  ),
                  TextButton(
                    onPressed: () async {
                      print('switch');
                      await cameraController.switchCamera();
                      setState(() {});
                    },
                    child: Text('CameraDialog_switch'.tr),
                  ),
                  TextButton(
                    onPressed: () {
                      print('cancel');
                      cameraController.disposeController();
                      Get.back();
                    },
                    child: Text('CameraDialog_cancel'.tr),
                  ),
                ],
              ),
            ),
          ],
        ),
      );
    },
  );
}
Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE BLURT!
Sort Order:  
  ·  2 years ago  ·  

Nice, i Now know flutter is not difficult just some simple language with a style 😆

Nice going


Posted from https://blurt.one

Congratulations, your post has been curated by @dsc-r2cornell. Also, find us on Discord

Manually curated by @abiga554

logo3 Discord.png

Felicitaciones, su publication ha sido votado por @dsc-r2cornell. También, encuéntranos en Discord